我需要SQL代码来解决表组合问题,如下所述:
表旧数据:表旧
name version status lastupdate ID
A 0.1 on 6/8/2010 1
B 0.1 on 6/8/2010 2
C 0.1 on 6/8/2010 3
D 0.1 on 6/8/2010 4
E 0.1 on 6/8/2010 5
F 0.1 on 6/8/2010 6
G 0.1 on 6/8/2010 7
表新数据:表新
name version status lastupdate ID
A 0.1 on 6/18/2010
#B entry deleted
C 0.3 on 6/18/2010 #version_updated
C1 0.1 on 6/18/2010 #new_added
D 0.1 on 6/18/2010
E 0.1 off 6/18/2010 #status_updated
F 0.1 on 6/18/2010
G 0.1 on 6/18/2010
H 0.1 on 6/18/2010 #new_added
H1 0.1 on 6/18/2010 #new_added
新数据和旧日期的差异:
B条目已删除
C条目版本已更新
E条目状态已更新
新增C1 / H / H1条目
我想要的是始终保持旧数据表中的ID - 名称映射关系,无论以后数据如何变化,a.k.a名称始终具有与之绑定的唯一ID号。
如果条目有更新,则更新数据,如果条目是新添加的,则插入表格,然后提供新分配的唯一ID。如果该条目已删除,请删除该条目,以后不再重复该ID。
但是,我只能使用带有简单选择或更新语句的SQL,那么我可能很难编写这样的代码,那么我希望有专业知识的人可以给出方向,不需要有关SQL变体,标准的不同细节sql代码作为样本就足够了。
提前致谢!
RGS
KC
====== 我在这里列出了我的草稿sql,但不确定它是否有效,有些专业人士请评论,谢谢!
创建表tmp为 从旧
中选择*更新tmp 其中的名称(从新选择名称)
插入到tmp(名称版本状态lastupdate ID) set idvar = max(从tmp中选择max(id))+ 1 选择*来自 (选择new.name new.version new.status new.lastupdate new.ID 从旧的,新的 其中old.name<> new.name)
从tmp删除 哪里 (选择???)
答案 0 :(得分:1)
让我从最后开始:
在#4中你会删除tmp中的所有行;你想说的是WHERE tmp.name NOT IN (SELECT name FROM new)
;同样#3语法不正确,但如果是,它会尝试插入所有行。
关于#2,为什么不在ID
上使用auto increment?
关于#1,如果您的tmp表与new相同,则查询#2-#4没有意义,除非您以某种方式更改(更新,插入,删除)new
表。
但(!),如果您确实更新了表格new
,并且ID
上有自动增量字段,并且您正在更新表格(使用{ {1}})来自应用程序然后您的整个过程不必要(!)。
所以,重要的是你不应该像上面那样设计系统。
要从应用程序端获取更新数据库中数据的概念,请查看示例here(php / mysql)。
另外,要使查询语法正确,请查看SET,INSERT,DELETE和SELECT命令的基本版本(不管怎样)。
答案 1 :(得分:1)
您从未提及您正在使用的DBMS,但如果您使用的是SQL Server,那么一个非常好的是SQL MERGE
语句。请参阅:http://www.mssqltips.com/tip.asp?tip=1704
MERGE语句基本上起作用 单独插入,更新和删除 所有声明都在同一个 声明。你指定一个“来源” 记录集和“目标”表,和 两者之间的联系。然后是你 指定数据修改的类型 那就是记录时发生的 两个数据之间是匹配的还是 不匹配。 MERGE非常有用, 特别是在装载时 数据仓库表,可以 非常大,需要具体 行是或时要采取的行动 不存在。
示例:
MERGE Products AS TARGET
USING UpdatedProducts AS SOURCE
ON (TARGET.ProductID = SOURCE.ProductID)
--When records are matched, update
--the records if there is any change
WHEN MATCHED AND TARGET.ProductName <> SOURCE.ProductName
OR TARGET.Rate <> SOURCE.Rate THEN
UPDATE SET TARGET.ProductName = SOURCE.ProductName,
TARGET.Rate = SOURCE.Rate
--When no records are matched, insert
--the incoming records from source
--table to target table
WHEN NOT MATCHED BY TARGET THEN
INSERT (ProductID, ProductName, Rate)
VALUES (SOURCE.ProductID, SOURCE.ProductName, SOURCE.Rate)
--When there is a row that exists in target table and
--same record does not exist in source table
--then delete this record from target table
WHEN NOT MATCHED BY SOURCE THEN
DELETE
--$action specifies a column of type nvarchar(10)
--in the OUTPUT clause that returns one of three
--values for each row: 'INSERT', 'UPDATE', or 'DELETE',
--according to the action that was performed on that row
OUTPUT $action,
DELETED.ProductID AS TargetProductID,
DELETED.ProductName AS TargetProductName,
DELETED.Rate AS TargetRate,
INSERTED.ProductID AS SourceProductID,
INSERTED.ProductName AS SourceProductName,
INSERTED.Rate AS SourceRate;
SELECT @@ROWCOUNT;
GO
答案 2 :(得分:1)
注意 - 如果您担心表现,可以跳过这整个答案:-)
如果您可以重新设计有2个表 - 一个包含数据,另一个包含名称 - ID链接。像
这样的东西table_original
name version status lastupdate
A 0.1 on 6/8/2010
B 0.1 on 6/8/2010
C 0.1 on 6/8/2010
D 0.1 on 6/8/2010
E 0.1 on 6/8/2010
F 0.1 on 6/8/2010
G 0.1 on 6/8/2010
和name_id
name ID
A 1
B 2
C 3
D 4
E 5
F 6
G 7
使用新数据集获取table_new时
注意:我认为这里的删除有点含糊不清
如果删除了该条目,请删除该条目 条目,以后不再重复使用该标识。
如果名称A被删除,并且在以后的一组更新中再次出现,你想要一个。重复使用标记为A或b的原始ID。生成一个新的ID?
如果是b。你需要删除列吗?在name_id和最后一步
4。设置已删除? = Y,其中name不在table_original
中和2.会排除已删除? = Y记录。
你也可以在没有name_id表的情况下做同样的事情,这是基于你需要table_old唯一的东西就是名字 - ID链接的逻辑。你需要的其他一切都在table_new,
答案 3 :(得分:1)
这适用于Informix,可准确显示所需的显示。人们会想,相同或类似的应该在MySQL中起作用。这里的技巧是将所有名称的联合放入临时表中并保持联接,以便可以比较其他两个的值。
SELECT DISTINCT name FROM old UNION SELECT DISTINCT name FROM new INTO TEMP _tmp; SELECT CASE WHEN b.name IS NULL THEN '' ELSE aa.name END AS name, CASE WHEN b.version IS NULL THEN '' WHEN a.version = b.version THEN a.version ELSE b.version END AS version, CASE WHEN a.status = b.status THEN a.status WHEN b.status IS NULL THEN '' ELSE b.status END AS status, CASE WHEN a.lastupdate = b.lastupdate THEN a.lastupdate WHEN b.lastupdate IS NULL THEN null ELSE b.lastupdate END AS lastupdate, CASE WHEN a.name IS NULL THEN '#new_added' WHEN b.name IS NULL THEN '#' || aa.name || ' entry deleted' WHEN a.version b.version THEN '#version_updated' WHEN a.status b.status THEN '#status_updated' ELSE '' END AS change FROM _tmp aa LEFT JOIN old a ON a.name = aa.name LEFT JOIN new b ON b.name = aa.name;
答案 4 :(得分:0)
起草的方法,我不知道它是否正常工作......
创建TRIGGER auto_next_id 在每个行的表格上插入后 开始 UPDATE表SET uid = max(uid)+ 1; END;
答案 5 :(得分:0)
如果我根据两个表中的注释很好地理解了您的需求,我认为如果您不合并或更新旧表,您可以简化很多问题,因为您需要的是表新的表ID表格存在时存在,新存在不存在时,对吗?
新记录:table new已经有了新的记录 - 好的(但是他们需要一个新的ID) 已删除的记录:它们不在新表中 - 好的 更新记录:已在表格中更新 - 确定(需要从旧表中复制ID) 未修改的记录:已在表中新建 - 确定(需要从旧表中复制ID)
所以你唯一需要做的就是: (a)将表格中的ID复制到新表格中 (b)在表格中不存在时,在表格中创建新的ID (c)将新表复制到旧表中。
(a)UPDATE new SET ID = IFNULL((旧ID WHERE new.name = old.name中的SELECT ID),0);
(b)UPDATE new SET ID = FUNCTION_TO GENERATE_ID(new.name)WHERE ID = 0;
(c)掉桌旧; CREATE TABLE old(select * from new);
由于我不知道您正在使用哪个SQL数据库,因此在(b)中您可以使用sql函数根据数据库生成唯一ID。使用SQL Server,newid(),使用postgresql(不是太旧的版本),now()似乎是一个很好的选择,因为它的精度看起来足够(但在其他数据库中不像MySQL那样,因为我认为精度仅限于秒)< / p>
编辑:对不起,我没有看到你使用的是sqlite和python。在这种情况下,您可以在python中使用str(uuid.uuid4())函数(uuid模块)生成uuid并在步骤(b)中填充ID为0的新表中的ID。这样,如果需要,您将能够加入2个独立的数据库而不会出现ID冲突。
答案 6 :(得分:0)
为什么不为此使用UUID?为插件生成一次,并将其保存到插件中,而不是插入到数据库中。现在您提到python,以下是如何生成它:
import uuid
UID = str(uuid.uuid4()) # this will yield new UUID string
当然,它不能保证全局唯一性,但是你在项目中获得相同字符串的可能性非常低。