如果更改了任何其他列字段,如何从具有相同主键的两个表中获取记录

时间:2014-04-22 05:09:05

标签: sql sql-server database

我之前的问题非常令人困惑。对于我的疏忽,我很抱歉。在这里,我再次发布了我的问题以及更多信息。

我的表A和表B具有相同的列名(名称,ID,年龄,日期,类,......)但行数不同。表B是表A的重复表,并且具有较少的行。我想知道的是,如果记录具有相同的主键(id)并且任何其他列字段(名称,年龄,日期,类,...)不同,我将如何检索记录。但是,有一个条件。虽然记录具有相同的主键,但是如果仅更改日期,则不应检索记录。只有当两个表具有相同的主键,日期不同且任何列字段发生更改时,才应检索记录。

由于大约有200k条记录,大约有100列,我想使用高级SQL,因为如果我使用Select.. from... where,我的SQL会太长,但我不知道哪条SQL使用

TableA

name    age  id  date
------  ---  --  ----------
David   11   1   11/01/2014
Claire  16   2   13/03/2014
Max     15   3   20/02/2014
John    14   4   19/09/2014
James   12   5   16/06/2014

TableB

name   age  id  date
-----  ---  --  ----------
Max    15   3   15/05/2014
Will   14   4   12/04/2014
Bill   12   7   11/04/2014
Paul   11   8   24/12/2013
Kevin  13   9   03/04/2014

预期输出:

TableA                       TableB

name  age  id  date          name  age  id  date
----  ---  --  ----------    ----  ---  --  ----------
John  14   4   19/09/2014    Will  14   4   12/04/2014

谢谢!

3 个答案:

答案 0 :(得分:0)

您可以使用strcmp()函数来比较字符串。 http://dev.mysql.com/doc/refman/5.0/en/string-comparison-functions.html#function_strcmp

例如,您想比较两个表中的名称和年龄,那么您的查询应如下所示:

select * from (select A.*,B.*,strcmp(concat(A.name,',',A.age),concat(B.name,',',B.age)) as diff from TableA A inner join TableB B on A.id = B.id)tablealias where tablealias.diff!=0

包括strcmp函数中的字段,如果它们发生更改,则会打扰

答案 1 :(得分:0)

最简单的方法是创建一个或多或少自动化的完整查询(制作一个使用EXPLAIN TABLE的小脚本,遍历列,忽略日期并进行选择)。每次更改表后,您都会重新运行该脚本。

更快的方法是引入一个在每次写入时更新的哈希列:触发器AFTER UPDATE和触发器AFTER INSERT计算所有重要列的哈希值(这也需要写下所有列,AFAIK),并将hashvalue写入hashfield。然后select只比较hashvalue。

如果您需要重复检查或UNIQUE KEY,该方法也很有用。在MySQL中,UNIQUE KEYs非常受限制,我认为16或32列是限制。

答案 2 :(得分:0)

由于您要检查编写where子句的所有列,因此可能会很繁琐,因此您可以使用information_schema.columns获取该表的列名,然后使用动态查询来检查列差异。

以下可能是解决您问题的方法。

--Simulate your table structure
CREATE TABLE TableA
(
    NAME VARCHAR(100),
    AGE INT,
    ID INT,
    DATE_COL DATETIME
)

CREATE TABLE TableB
(
    NAME VARCHAR(100),
    AGE INT,
    ID INT,
    DATE_COL DATETIME
)

--Data for testing
INSERT INTO TABLEA(NAME, AGE, ID, DATE_COL) VALUES('David',11,1,'01/11/2014')
INSERT INTO TABLEA(NAME, AGE, ID, DATE_COL) VALUES('Claire',16,2,'03/13/2014')
INSERT INTO TABLEA(NAME, AGE, ID, DATE_COL) VALUES('Max',15,3,'02/20/2014')
INSERT INTO TABLEA(NAME, AGE, ID, DATE_COL) VALUES('John',14,4,'09/19/2014')
INSERT INTO TABLEA(NAME, AGE, ID, DATE_COL) VALUES('James',12,5,'06/16/2014')

INSERT INTO TABLEB(NAME, AGE, ID, DATE_COL) VALUES('Max',15,3,'05/15/2014')
INSERT INTO TABLEB(NAME, AGE, ID, DATE_COL) VALUES('Will',14,4,'04/12/2014')
INSERT INTO TABLEB(NAME, AGE, ID, DATE_COL) VALUES('Bill',12,7,'04/11/2014')
INSERT INTO TABLEB(NAME, AGE, ID, DATE_COL) VALUES('Paul',11,8,'12/24/2013')
INSERT INTO TABLEB(NAME, AGE, ID, DATE_COL) VALUES('Kevin',13,9,'04/03/2014')


--Solution Starts from here 
CREATE TABLE #TableCols
(
    ID INT IDENTITY(1,1),
    COLUMN_NAME VARCHAR(1000)
)


--since both tables have same columns you can take columns of any 1 table
INSERT INTO #TableCols
(COLUMN_NAME)
SELECT COLUMN_NAME
FROM information_schema.columns
WHERE table_name = 'TableA';

DECLARE @STARTCOUNT INT, @MAXCOUNT INT, @COL_NAME VARCHAR(1000), @QUERY VARCHAR(8000), @SUBQUERY VARCHAR(8000)

SELECT @STARTCOUNT = 1, @MAXCOUNT = MAX(ID) FROM #TableCols;
SELECT @QUERY = '', @SUBQUERY = ''

WHILE(@STARTCOUNT <= @MAXCOUNT)
BEGIN
    SELECT @COL_NAME = COLUMN_NAME FROM #TableCols WHERE ID = @STARTCOUNT;

    IF(@COL_NAME != 'DATE_COL' AND @COL_NAME != 'ID')
    BEGIN
        SET @SUBQUERY = @SUBQUERY + ' A.' + @COL_NAME + ' != B.' + @COL_NAME + ' OR ';
    END

    SET @STARTCOUNT = @STARTCOUNT + 1
END

SET @SUBQUERY = LEFT(@SUBQUERY, LEN(@SUBQUERY) - 3);
SET @QUERY = 'SELECT A.*, B.* FROM TableA A INNER JOIN TableB B ON A.ID = B.ID WHERE A.DATE_COL != B.DATE_COL AND (' + @SUBQUERY + ')';
EXEC (@QUERY);

希望这有帮助。