2015-03-12 5 views
0

Я хочу использовать результат запроса внутри другого запроса SQLite3. Например, рассмотрим следующую таблицу в базе данных SQLite.Эффективное заявление SQLite3

No Name Value1 Value2 Value3 Salary 
------------------------------------------ 
1 Kid1  100  0  0  300 
2 Kid2  200  700  0  400 

Вышеприведенная таблица может быть создана с использованием следующего кода. Многие благодаря Mike Sherrill 'Cat Recall для обмена этим кодом.

CREATE TABLE test (
    no integer primary key, 
    name varchar(15) not null, 
    value1 integer not null, 
    value2 integer not null, 
    value3 integer not null, 
    salary decimal(13, 2) not null 
); 
INSERT INTO "test" VALUES(1,'Kid1',100,0,0,300); 
INSERT INTO "test" VALUES(2,'Kid2',200,700,0,400); 

Теперь мне нужно обновить таблицу SQLite3, используя следующее правило.

Для каждой строки обновите Salary = Salary + Value1/N, где N обозначает количество нулевых значений в (Value2 и Value 3) в строке.

В приведенном выше примере, после выполнения команды я хотел бы получить со следующей таблицей

No Name Value1 Value2 Value3 Salary 
------------------------------------------ 
1 Kid1  100  0  0  350 
2 Kid2  200  700  0  600 
+0

Этот ответ полезный для вас? http://stackoverflow.com/questions/17897811/sql-sql-lite-counting-records-after-filtering – BookOfGreg

+0

* Где N обозначает количество значений, отличных от нуля, в (Value2 и Value 3) в строке . * 'Non-zero' или' zero'? В соответствии с вашей итоговой таблицей это должно быть «zero» ...! – minarmahmud

ответ

1

Paste CREATE TABLE и INSERT заявления в ваш вопрос, чтобы получить больше ответов. Многие люди не будут тратить время на обратное проектирование структуры базы данных. (Для SQLite используйте .dump your-table-name.)

Чтобы ответить на ваш вопрос, я думаю, что важно научиться этому. Я также думаю, что важно не делать этого. См. Текст и код ниже горизонтального правила ниже.

CREATE TABLE test (
    no integer primary key, 
    name varchar(15) not null, 
    value1 integer not null, 
    value2 integer not null, 
    value3 integer not null, 
    salary decimal(13, 2) not null 
); 
INSERT INTO "test" VALUES(1,'Kid1',100,0,0,300); 
INSERT INTO "test" VALUES(2,'Kid2',200,700,0,400); 

Этот оператор SELECT дает нам количество нулей в каждой строке. Нам не важно, какой столбец (value2 или Value3) нуль появляется.

select no, case when value2 = 0 then 1 else 0 end as num_zeroes from test 
union all 
select no, case when value3 = 0 then 1 else 0 end from test; 
 
no   num_zeroes 
---------- ---------- 
1   1   
2   0   
1   1   
2   1   

Следующее утверждение суммирует количество нулей для нас.

select no, sum(num_zeroes) as num_zeroes 
from (select no, case when value2 = 0 then 1 else 0 end as num_zeroes from test 
     union all 
     select no, case when value3 = 0 then 1 else 0 end from test) as zeroes 
group by no; 
 
no   num_zeroes 
---------- ---------- 
1   2   
2   1   

Я думаю, что результат достаточно полезным, чтобы сделать вид из него.

create view num_zeroes as 
select no, sum(num_zeroes) as num_zeroes 
from (select no, case when value2 = 0 then 1 else 0 end as num_zeroes from test 
     union all 
     select no, case when value3 = 0 then 1 else 0 end from test) as zeroes 
group by no; 

Теперь мы можем сделать расчет с помощью соединения и небольшой арифметики. Этот оператор SELECT показывает, как работают куски.

select 
    t1.no, t1.value1, t1.salary, 
    t2.num_zeroes, t1.salary + (t1.value1/t2.num_zeroes) as new_salary 
from test t1 
inner join num_zeroes t2 on t1.no = t2.no; 

Настоящий обновляет.

update test 
set salary = (select t1.salary + (t1.value1/t2.num_zeroes) 
       from test t1 
       inner join num_zeroes t2 on t1.no = t2.no 
       where t1.no = test.no); 


Проблема такого подхода является то, что кто-то может запустить обновление более чем один раз. Если это произойдет, может быть сложно восстановить исходные значения.

Вместо этого создайте таблицу для истории окладов. Плохие обновления легче исправить, когда вы используете таблицу истории окладов.

Я использовал дату «9999-12-31» для представления «конца времени».

pragma foreign_keys = on; 

create table salary_history (
    no integer not null, 
    start_date date not null, 
    end_date date not null default '9999-12-31', 
    salary decimal(13, 2) not null, 
    foreign key (no) references test (no), 
    primary key (no, start_date) 
); 

Вставьте пару строк, чтобы мы начали. Я вытащил «2015-01-01» из воздуха.Я не знаю, какие значения value1, value2 и value3 означают в вашей исходной таблице, поэтому я не знаю, следует ли их переместить в «зарплата». Я оставил их в покое.

insert into salary_history values 
(1, '2015-01-01', '9999-12-31', 300), 
(2, '2015-01-01', '9999-12-31', 400); 

Я думаю, что представление о текущих зарплатах - это, как правило, хорошая идея, и это облегчает последующие вычисления.

create view current_salary as 
select no, start_date, end_date, salary 
from salary_history 
where current_date >= start_date 
    and current_date < end_date; 

Чтобы обновить историю окладов, сверните транзакцию вокруг двух операторов SQL UPDATE. Первая из них прекращает текущую зарплату, устанавливая дату окончания на текущую дату. Вторая вставляет новую строку, которая станет текущей зарплатой.

begin transaction; 

update salary_history 
set end_date = current_date 
where end_date = '9999-12-31'; 

insert into salary_history 
select 
    t1.no, current_date, '9999-12-31', 
    t1.salary + (t3.value1/t2.num_zeroes) as new_salary 
from current_salary as t1 
inner join num_zeroes as t2 on t1.no = t2.no 
inner join test as t3 on t1.no = t3.no; 

commit; 
Смежные вопросы