需要SQL语句专注于表的组合,但条目始终具有唯一ID

时间:2010-06-08 03:01:13

标签: sql mysql sqlite unique combinations

我需要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,但不确定它是否有效,有些专业人士请评论,谢谢!

1.将旧表重复为tmp以进行商店更新

创建表tmp为 从旧

中选择*

2.更新到tmp,其中“name”在旧表和新表中相同

更新tmp 其中的名称(从新选择名称)

3.将不同的“名称”(旧与新)插入tmp并分配新ID

插入到tmp(名称版本状态lastupdate ID) set idvar = max(从tmp中选择max(id))+ 1 选择*来自   (选择new.name new.version new.status new.lastupdate new.ID   从旧的,新的   其中old.name<> new.name)

4。从tmp表中删除已删除的条目(例如B)

从tmp删除 哪里 (选择???)

7 个答案:

答案 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时

  1. TRUNCATE table_original
  2. INSERT INTO name_id(table_new中的名称不在name_id中)
  3. 将table_new复制到table_original
  4. 注意:我认为这里的删除有点含糊不清

      

    如果删除了该条目,请删除该条目   条目,以后不再重复使用该标识。

    如果名称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

当然,它不能保证全局唯一性,但是你在项目中获得相同字符串的可能性非常低。