我有2张桌子。
一个表定义了客户连接:
CREATE TABLE IF NOT EXISTS `cust_connections` (
`id` int(11) NOT NULL,
`short_name` char(15) COLLATE utf8_unicode_ci NOT NULL,
`source_fnn` char(10) COLLATE utf8_unicode_ci NOT NULL,
`dest_fnn` char(10) COLLATE utf8_unicode_ci NOT NULL,
`service_type` char(32) COLLATE utf8_unicode_ci NOT NULL,
`ladder_side` char(10) COLLATE utf8_unicode_ci NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO `cust_connections` (`id`, `short_name`, `source_fnn`, `dest_fnn`, `service_type`, `ladder_side`) VALUES
(1, 'cust1', 'N2843453A', '', 'HD_300_Connect', 'src only'),
(2, 'cust2', '', 'N2843600A', 'HD_300_Connect', 'dest only'),
(3, 'cust3', 'N2720257O', 'N2731164O', 'DVB25_188byte', 'both'),
(4, 'cust4', 'N27xxx7O', 'N2731164O', 'DVB25_188byte', 'src ukn'),
(5, 'cust4', 'N27xxx7O', '', 'DVB25_188byte', 'ukn +blk');
ALTER TABLE `cust_connections`
ADD PRIMARY KEY (`id`);
ALTER TABLE `cust_connections`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=18;
另一张桌子定义了设备:
CREATE TABLE IF NOT EXISTS `cust_port` (
`id` smallint(11) NOT NULL,
`system_name` char(32) COLLATE utf8_unicode_ci NOT NULL,
`slot_no` char(2) COLLATE utf8_unicode_ci NOT NULL,
`port_no` char(2) COLLATE utf8_unicode_ci NOT NULL,
`port_fnn` char(9) COLLATE utf8_unicode_ci NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO `cust_port` (`id`, `system_name`, `slot_no`, `port_no`, `port_fnn`) VALUES
(1, '01-06C2:source', '7', '1', 'N2843453A'),
(2, '01-27B4:dest', '1', '2', 'N2843600A'),
(3, '01-27B6:source+dst', '17', '3', 'N2720257O'),
(4, '01-27B6:dst+src', '17', '3', 'N2731164O'),
(5, '01-32C6:dup_fnn1', '1', '2', 'N2845070O'),
(26, '01-32C6:dup_fnn2', '1', '3', 'N2845070O'),
(27, '01-32D6:no_fnn', '1', '4', ''),
(28, '01-32D6:diff_fnn', '1', '4', 'x123456');
ALTER TABLE `cust_port`
ADD PRIMARY KEY (`id`);
ALTER TABLE `cust_port`
MODIFY `id` smallint(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=29;
SQl结果是:
cc_id short_name source_fnn dest_fnn service_type ladder_side src_system_name src_slot_no src_port_no src_port_fnn dst_system_name dst_slot_no dst_port_no dst_port_fnn
1 cust1 N2843453A HD_300_Connect src only 01-06C2:source 7 1 N2843453A 01-32D6:no_fnn 1 4
2 cust2 N2843600A HD_300_Connect dest only 01-32D6:no_fnn 1 4 01-27B4:dest 1 2 N2843600A
3 cust3 N2720257O N2731164O DVB25_188byte both 01-27B6:source+dst 17 3 N2720257O 01-27B6:dst+src 17 3 N2731164O
4 cust4 N27xxx7O N2731164O DVB25_188byte src ukn NULL NULL NULL NULL 01-27B6:dst+src 17 3 N2731164O
5 cust4 N27xxx7O DVB25_188byte ukn +blk NULL NULL NULL NULL 01-32D6:no_fnn 1 4
我正在加入这两张桌子。
问题是,如果port_fnn为null,我想排除该行,但如果任何客户源或目标fnns为空,则显示该行。
我正在进行左(自)联接以匹配源fnn和源fnn的fnn。不幸的是,我的客户fnns必须能够具有空值。
如果设备表中没有空值,我的查询效果很好。 我的疑问是:
SELECT
cc.id AS cc_id, short_name,source_fnn, dest_fnn, service_type,ladder_side,
src.system_name AS src_system_name,
src.slot_no AS src_slot_no,
src.port_no AS src_port_no,
src.port_fnn AS src_port_fnn,
dst.system_name AS dst_system_name,
dst.slot_no AS dst_slot_no,
dst.port_no AS dst_port_no,
dst.port_fnn AS dst_port_fnn
FROM cust_connections cc
LEFT JOIN cust_port src on cc.source_fnn=src.port_fnn
LEFT JOIN cust_port dst on cc.dest_fnn=dst.port_fnn
在我的结果集中: 第1行 - 仅包含源fnn。我希望结果对于目标字段为空,即:
cc_id short_name source_fnn dest_fnn service_type ladder_side src_system_name src_slot_no src_port_no src_port_fnn dst_system_name dst_slot_no dst_port_no dst_port_fnn
1 cust1 N2843453A HD_300_Connect src only 01-06C2:source 7 1 N2843453A NULL NULL NULL NULL
查询正在检测null fnn并使用没有关联fnn的设备进行填充。即:01-32D6:no_fnn。
第2行的source_system_name和第5行的dst_system_name也会出现同样的问题。
答案 0 :(得分:1)
您可以添加where
子句,如:
where (cc.source_fnn is null or cc.dest_fnn is null)
or (src.port_fnn is not null or dst.port_fnn is not null)
现在它将始终显示空source_fnn
或dest_fnn
的行。如果两者都填满,它将过滤掉匹配的port_fnn
列为空的行。
因此,您将获得缺少外键的行,但会禁止外键引用具有空列的行的行。至少那是我认为你正在寻找的东西。如果不是,请澄清你的问题。
答案 1 :(得分:1)
我认为您尝试做的事情可以通过每个相应的源/目标列的IF()来完成MASK的名称和端口。大多数时候人们会尝试做一些事情来预防空值并显示类似空字符串的东西......相反,你想要反过来...如果“port_fnn”为空,你想要隐藏这些元素。
所以我为每一列做了一个IF(表达式,结果如果为true,结果为false)。因此,如果port_fnn为NULL,则显示null作为结果,否则返回列的任何内容(系统名称,插槽,端口等)
SELECT
cc.id AS cc_id,
short_name,
source_fnn,
dest_fnn,
service_type,ladder_side,
if( src.port_fnn = '', NULL, src.system_name ) AS src_system_name,
if( src.port_fnn = '', NULL, src.slot_no ) AS src_slot_no,
if( src.port_fnn = '', NULL, src.port_no ) AS src_port_no,
if( src.port_fnn = '', NULL, src.port_fnn ) AS src_port_fnn,
if( dst.port_fnn = '', NULL, dst.system_name ) AS dst_system_name,
if( dst.port_fnn = '', NULL, dst.slot_no ) AS dst_slot_no,
if( dst.port_fnn = '', NULL, dst.port_no ) AS dst_port_no,
if( dst.port_fnn = '', NULL, dst.port_fnn ) AS dst_port_fnn
FROM
cust_connections cc
LEFT JOIN cust_port src
on cc.source_fnn = src.port_fnn
LEFT JOIN cust_port dst
on cc.dest_fnn = dst.port_fnn
我调整了上面的查询以处理您的数据... NULL与空字符串不同。我将表和示例数据复制到SQL Fiddle,然后复制上面的查询。它似乎分别显示了源和目的地的NULLS。
答案 2 :(得分:1)
''(空字符串)不是NULL。 (哪个sqlfiddle输出为“(null)”。)
在文字中,不要写“NULL”或“< NULL>”或“null”或“(null)”引用您在问题中最初的空字符串。要清楚什么是''和什么是NULL。
''=''但是NULL<>空值。因此,当等式测试涉及''时,LEFT JOIN会在列cc.source_fnn和src.port_fnn之间以及列cc.dest_fnn和cust_port port_fnn之间找到匹配项。但是你不希望LEFT JOIN匹配那些行。
你可以这样说:
声明所有_fnn列可以为空,即为NULL(默认值)而不是NOT NULL,并在您现在使用''(空字符串)的表中使用NULL。然后您的查询将给出正确的答案!
要求port_fnn<> '':
FROM cust_connections cc
LEFT JOIN cust_port src
ON cc.source_fnn=src.port_fnn AND cc.source_fnn <> ''
LEFT JOIN cust_port dst
ON cc.dest_fnn=dst.port_fnn AND cc.dest_fnn <> '';
在LEFT JOIN之前从cust_port中删除这些行:
FROM cust_connections cc
LEFT JOIN
(SELECT * FROM cust_port WHERE port_fnn <> ''
) src
ON cc.source_fnn=src.port_fnn
LEFT JOIN
(SELECT * FROM cust_port WHERE port_fnn <> ''
) dst
ON cc.dest_fnn=dst.port_fnn;
Sqlfiddle for 1 using NULL和for 2 & 3 using ''。它们添加了第二个cust_port行,缺少port_fnn以显示上面给出了正确的结果。您的查询与''一起使用时会错误地生成其他虚假行。
如果你希望LEFT JOIN中的NULL显示为输出上的空字符串,那么你可以对这些列使用IFNULL:
IFNULL(dst.port_fnn,'')AS dst_port_fnn
答案 3 :(得分:0)
[这个答案是在qeustion的早期版本的上下文中,其中示例输入不清楚地描述了空字符串,即''为NULL /&lt; NULL&gt; / null所以看起来“”值为NULL。如果它们为NULL,则应用此答案。 Sqlfiddle]
错误的“期望输出”
“所需输出”中的equip4 1/2是一个错误,您需要从端口ID 2通过4444装备1 1/2。在您纠正之后,所需的输出就是您在其他地方描述的(不清楚)。
NULL port_fnn不是问题
null port_fnn没有从查询中将任何内容放入表中。 LEFT JOIN永远不会匹配它。
您想要哪些行?
你不清楚。您没有解决的唯一行是非NULL源source_fnn或dest_fnn没有匹配的port_fn。然后在LEFT JOIN输出中,它与NULL port_fnn info配对。
如果你不想要那些行,那就太奇怪了。您不仅没有cust_connection的行,而且扩展信息的另一半将被抛弃。也许你只会丢弃源和dest都是非NULL并且匹配的行。还是很奇怪。你必须告诉我们你是否想要这些行。大概你想要他们,因为他们在你的询问中。
如果每个source_fnn和dest_fnn都有匹配的port_fnn,即从source_fnn adn dest_fnn到port_fnn有外键,那么这种情况永远不会发生,并且你的查询是正确的。
所以您的查询似乎没问题。
似乎您错误地猜到了NULL port_fnn无法解释为什么它与您错误的预期输出不同。