我有以下SQL Server查询:
SELECT TOP (100) PERCENT
dbo.cct_prod_plc_log_data.wc,
dbo.cct_prod_plc_log_data.loc,
dbo.cct_prod_plc_log_data.ord_no,
dbo.cct_prod_plc_log_data.ser_lot_no,
dbo.cct_prod_plc_log_data.line,
ISNULL(dbo.imlsmst_to_sfdtlfil.ItemNo, '') AS ItemNo,
ISNULL(dbo.imlsmst_to_sfdtlfil.BldSeqNo, '') AS BldSeqNo,
ISNULL(dbo.imlsmst_to_sfdtlfil.BldOrdNo, '') AS BldOrdNo,
ISNULL(dbo.imlsmst_to_sfdtlfil.StringItemNo, '') AS StringItemNo,
ISNULL(dbo.imlsmst_to_sfdtlfil.StringSerLotNo, '') AS StringSerLotNo,
MAX(dbo.cct_prod_plc_log_data.InsertDateTime) AS LatestDateTime,
MIN(ISNULL(dbo.cct_prod_plc_log_data.erp_transaction_id, 0)) AS MinimumErpID,
ISNULL(dbo.imlsmst_to_sfdtlfil.QtyOnHand, 0) AS QtyOnHand
FROM
dbo.cct_prod_plc_log_data
LEFT OUTER JOIN dbo.imlsmst_to_sfdtlfil
ON dbo.cct_prod_plc_log_data.ser_lot_no = dbo.imlsmst_to_sfdtlfil.SerLotNo
AND dbo.cct_prod_plc_log_data.ord_no = dbo.imlsmst_to_sfdtlfil.OrderNo
AND dbo.cct_prod_plc_log_data.line = dbo.imlsmst_to_sfdtlfil.Bin
WHERE
( dbo.cct_prod_plc_log_data.erp_transaction_id < 3 OR dbo.cct_prod_plc_log_data.erp_transaction_id IS NULL )
AND (dbo.cct_prod_plc_log_data.wc <> '')
AND (dbo.cct_prod_plc_log_data.loc <> '')
AND (dbo.cct_prod_plc_log_data.line <> '')
GROUP BY
dbo.cct_prod_plc_log_data.wc,
dbo.cct_prod_plc_log_data.loc,
dbo.cct_prod_plc_log_data.ord_no,
dbo.cct_prod_plc_log_data.ser_lot_no,
dbo.cct_prod_plc_log_data.line,
dbo.imlsmst_to_sfdtlfil.ItemNo,
dbo.imlsmst_to_sfdtlfil.BldSeqNo,
dbo.imlsmst_to_sfdtlfil.BldOrdNo,
dbo.imlsmst_to_sfdtlfil.StringItemNo,
dbo.imlsmst_to_sfdtlfil.StringSerLotNo,
dbo.imlsmst_to_sfdtlfil.QtyOnHand
ORDER BY dbo.cct_prod_plc_log_data.ord_no DESC
它在3个字段的两个表之间包含一个左外部联接。根据当前结构,如果右表(dbo.imlsmst_to_sfdtlfil)中的3个Joined字段中的任何一个为空或丢失,则左查询中的字段应返回null。
如何确定导致连接失败的3个字段中的哪个?我想将它们彼此区分开。谢谢。
(例如,存在ser_lot_no和ord_no,但bin为null,而存在bin和ord_no,但ser_lot_no为null。)
答案 0 :(得分:0)
将其更改为内部联接,并注释掉除其中一种情况以外的所有情况,然后一次取消对它们的注释,直到数据再次消失-这是错误的情况。如果即使只有一种情况也没有数据,那就是错误的情况:
SELECT
c.wc,
c.loc,
c.ord_no,
c.ser_lot_no,
c.line,
COALESCE(i.ItemNo, '') AS ItemNo,
COALESCE(i.BldSeqNo, '') AS BldSeqNo,
COALESCE(i.BldOrdNo, '') AS BldOrdNo,
COALESCE(i.StringItemNo, '') AS StringItemNo,
COALESCE(i.StringSerLotNo, '') AS StringSerLotNo,
MAX(c.InsertDateTime) AS LatestDateTime,
MIN(COALESCE(c.erp_transaction_id, 0)) AS MinimumErpID,
COALESCE(i.QtyOnHand, 0) AS QtyOnHand
FROM
dbo.cct_prod_plc_log_data c
INNER JOIN dbo.imlsmst_to_sfdtlfil i
ON
c.ser_lot_no = i.SerLotNo
--AND c.ord_no = i.OrderNo
--AND c.line = i.Bin
WHERE
( c.erp_transaction_id < 3 OR c.erp_transaction_id IS NULL )
AND (c.wc <> '')
AND (c.loc <> '')
AND (c.line <> '')
GROUP BY
c.wc,
c.loc,
c.ord_no,
c.ser_lot_no,
c.line,
COALESCE(i.ItemNo, ''),
COALESCE(i.BldSeqNo, '')
COALESCE(i.BldOrdNo, '')
COALESCE(i.StringItemNo, '')
COALESCE(i.StringSerLotNo, '')
COALESCE(i.QtyOnHand, 0)
ORDER BY c.ord_no DESC
使用INNER JOIN比OUTER JOIN更为明显,因为大多数查询工具都提供行数,并且更容易看到行数从99990变为100000,而不是盯着100000的行寻找不应该为空的10行。会
如果您有2个以上的表,请注释掉您的选择块,加上*,除2个表之外的所有表:
SELECT *
/* columns,list,here,blah,blah */
FROM
table1
JOIN table2 ON ...
--JOIN table3 on ...
--JOIN table4 on ...
运行它,获取预期的行数,然后继续取消注释越来越多的表。如果在任何时候您的行计数发生意外变化(当您期望更少时,行数就会增加,或者当您期望更高时,行数会减少)。 如果行数增加,则可能是笛卡尔积,应该通过添加额外的连接条件来解决,而不是通过乱打DISTINCT来解决
其他重要提示:
感谢您的见解和提示。但是,我的问题更多的是一个问题,即如何合并有关哪个字段导致联接失败的信息,这是永久添加而不是一次性审核。有什么见解吗? –
我说:
您无法做到这一点,数据库无法告诉您“哪个字段”没有解决,因为其中大多数没有解决。要了解我的意思,请运行以下命令:
SELECT
-- replace .id with the name of the pk column
CONCAT('Cannot join c[', c.id, '] to i[', i.id, '] because: ',
CASE
WHEN COALESCE(c.ser_lot_no, 'null') != COALESCE(i.SerLotNo, 'null ') THEN 'c.ser_lot_no != i.SerLotNo, '
END,
CASE
WHEN COALESCE(c.ord_no, 'null') != COALESCE(i.OrderNo, 'null ') THEN 'c.ord_no != i.OrderNo, '
END,
CASE
WHEN COALESCE(c.line, 'null') != COALESCE(i.Bin, 'null ') THEN 'c.line != i.Bin, '
END
)
FROM
dbo.cct_prod_plc_log_data c
CROSS JOIN dbo.imlsmst_to_sfdtlfil i
它要求数据库将每一行连接到其他每一行,然后查看该行上的值并计算出是否可以连接。如果表c有1000行,表i有2000行(和c中的每一行最多与i)中的2行匹配,您将获得200万行的结果集,其中1998000行是“因为...而无法将该行加入该行”
A.id
1
2
3
B.id
3
4
5
A中唯一与B连接的行是“ 3”,即使如此,A中的“ 3”也不会与B中的4或5连接,B中的3也不会与A中的1或2连接。 。对于一组匹配的行,您有8条抱怨说这些行不匹配(总共3x3行,减去一个匹配项)
因此,不能,因为条件X,您不可能使数据库告诉您该表中的哪些行与该表中的哪些行不匹配,因为答案是“几乎所有这些行都不匹配”而“全部”可能是数亿
如果您有一些应该一直有效的联接列,而有些有时却不可行,则变得稍微可行一点。
SELECT CASE WHEN a.something != b.other THEN 'this row would fail because something != other' END
FROM a JOIN b ON a.id = b.id --and a.something = b.other
再想一想;关系数据库以数据相关的思想为中心,您甚至可以在约束条件下实施它:“除非在行X中存在A,B和C值,否则不允许在其中插入X行表的D,E和F列”
这就是确保连接成功(关系完整性)时应该使用的方法,不允许任何旧的废话进入数据库,然后尝试确定哪些行可能已经连接到了其他行(如果仅存在一些行) A列中的拼写错误,即使B / C与E / F匹配,也不能与D完全匹配。