我希望在SQLite3的另一个查询中使用查询结果。例如,请考虑SQLite数据库中的下表。
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表示行中(值2和值3)中零值的数量。
在上面的例子中,执行命令后我想得到下表
No Name Value1 Value2 Value3 Salary
------------------------------------------
1 Kid1 100 0 0 350
2 Kid2 200 700 0 600
答案 0 :(得分:1)
将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的含义是什么,所以我不知道它们是否应该被移入“salary_history”。我让他们独自一人。
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;