5

我需要 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 - 名称映射关系,无论以后数据如何更改,也就是名称始终具有与之绑定的唯一 ID 号。

如果条目有更新,则更新数据,如果条目是新添加的,则插入到表中,然后给出新分配的唯一 ID。如果条目已删除,请删除该条目并且以后不要重复使用该 ID。

但是,我只能使用带有简单选择或更新语句的SQL,那么我编写这样的代码可能对我来说太难了,那么我希望有专业知识的人可以指导一下,关于不同的SQL变体不需要详细说明,一个标准的sql代码为样品就足够了。

提前致谢!

Rgs

KC

======== 我在这里列出了我的草稿sql,但不确定它是否有效,请有专业知识的人发表评论,谢谢!

1.复制旧表作为存储更新的tmp

创建表 tmp 作为 select * from old

2.更新到新旧表中“名称”相同的tmp

更新 tmp where name in (select name from new)

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

insert into tmp (name version status lastupdate ID) set idvar = max(select max(id) from tmp) + 1 select * from (select new.name new.version new.status new.lastupdate new.ID from old, new where旧名称 <> 新名称)

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

从 tmp where 中删除(选择 ???)

4

7 回答 7

1

让我从头开始:

在 #4 中,您将删除 tmp 中的所有行;你想说的有WHERE tmp.name NOT IN (SELECT name FROM new);同样,#3 的语法不正确,但如果是,它会尝试插入所有行。

关于#2,为什么不在?上使用自动增量ID

关于 #1,如果您的 tmp 表与新表相同,则查询 #2-#4 没有任何意义,除非您new以某种方式更改(更新、插入、删除)表。

但是(!),如果您确实更新了表格new并且它有一个自动增量字段,ID并且如果您ID从应用程序正确更新表格(使用),那么您的整个过程是不必要的(!)。

因此,重要的是您不应该将系统设计为像上面那样工作。

要从应用程序端获取更新数据库中数据的概念,请查看此处的示例(php/mysql)。

此外,要使查询的语法正确,请通过基本版本的 SET、INSERT、DELETE 和 SELECT 命令(无法解决此问题)。

于 2010-06-08T07:51:13.273 回答
1

您从未提及您使用的是什么 DBMS,但如果您使用的是 SQL Server,那么一个非常好的方法就是 SQLMERGE语句。见: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
于 2010-06-08T20:28:19.707 回答
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

注意:我认为这里的删除有点模棱两可

如果条目已删除,请删除该条目并且以后不要重复使用该 ID。

如果名称 A 被删除,并且在以后的一组更新中再次出现,您是否想要 a。重复使用标记为 A 或 b 的原始 ID。生成一个新的ID?

如果是b。你需要一列删除?在 name_id 和最后一步

4. 设置删除?= Y 其中名称不在 table_original 中

和 2. 会排除 Deleted 吗?= Y 记录。

您也可以在没有 name_id 表的情况下执行相同的操作,因为您需要从 table_old 获得的唯一内容就是名称 - ID 链接。您需要的其他一切都在 table_new 中,

于 2010-06-16T05:27:07.397 回答
1

这在 Informix 中有效,并准确地提供了您需要的显示。有人会认为,相同或相似的应该在 MySQL 中工作。这里的技巧是将所有名称的并集放入一个临时表中并在其上左连接,以便可以比较其他两个的值。

SELECT DISTINCT name FROM old
联盟
SELECT DISTINCT name FROM new
进入温度_tmp;

选择
  案例当 b.name 为 NULL THEN ''
       ELSE aa.name
       结束作为名称,
  案例当 b.version 为 NULL THEN ''
       当 a.version = b.version THEN a.version
       ELSE b.版本
       END AS 版本,
  当 a.status = b.status THEN a.status 时的情况
       当 b.status 为 NULL THEN ''
       ELSE b.状态
       结束作为状态,
  当 a.lastupdate = b.lastupdate THEN a.lastupdate 时的情况
       当 b.lastupdate 为空时,则为空
       ELSE b.lastupdate
       结束为最后更新,
  CASE WHEN a.name 为 NULL THEN '#new_added'
       当 b.name 为 NULL 时,'#' || aa.name || '条目已删除'
       当 a.version b.version THEN '#version_updated'
       当 a.status b.status THEN '#status_updated'
       别的 ''
  结束更改
  FROM _tmp aa
  LEFT JOIN 旧 a
         ON a.name = aa.name
  左加入新 b
         ON b.name = aa.name;
于 2010-06-18T00:24:35.770 回答
0

一个草拟的方法,我不知道它是否工作正常......

CREATE TRIGGER auto_next_id AFTER INSERT ON table FOR EACH ROW BEGIN UPDATE table SET uid = max(uid) + 1 ; 结尾;

于 2010-06-17T07:00:01.510 回答
0

如果我根据两个表中的注释很好地理解了您的需求,我认为如果您不合并或更新旧表,您可以简化很多问题,因为您需要的是新表,其中的 ID 在表 old 时当它们不存在时,它们存在并且新的 ID,对吗?

新记录:新表已有新记录 - 好的(但它们需要新的 ID) 已删除的记录:它们不在新表中 - 好的 更新的记录:已在新表中更新 - 好的(需要从旧表中复制 ID)未修改的记录:已经在新表中 - 好的(需要从旧表中复制 ID)

因此,您唯一需要做的就是:(a)将旧表中的 ID 复制到新表(当它们存在时)(b)当它们在旧表中不存在时在新表中创建新 ID(c)将新表复制到表旧。

(a) UPDATE new SET ID = IFNULL((SELECT ID FROM old WHERE new.name = old.name),0);

(b) 更新新的 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,因为我认为精度仅限于秒)

编辑:对不起,我没有看到你使用 sqlite 和 python。在这种情况下,您可以在 python 中使用 str(uuid.uuid4()) 函数(uuid 模块)来生成 uuid 并将 ID 填充到步骤 (b) 中 ID = 0 的新表中。这样,如果需要,您将能够加入 2 个独立的数据库,而不会在 ID 上发生冲突。

于 2010-06-23T02:01:53.307 回答
0

你为什么不为此使用 UUID?为插件生成一次,并将其合并/保留到插件中,而不是数据库中。既然你提到了 python,下面是如何生成它:

import uuid
UID = str(uuid.uuid4()) # this will yield new UUID string

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

于 2010-06-25T19:54:57.980 回答