mysql 返回所有行,MySQL返回所有行,其中一列包含集合中的任何关键字,但仅包含关键字...

有没有一种方法可以选择其中一列仅包含,但可以包含任意数量的预定义值的行?

我一直在使用它,但是它返回的行中我的列至少包含一个值(我知道这正是它应该做的).

但是我正在寻找一种方法,仅选择在关键字列中只有我的关键字的行.

SELECT *

FROM

`products`.`product`

WHERE

keywords LIKE '%chocolate%'

AND keyword LIKE '%vanilla%';

示例关键字:巧克力,糖,牛奶,燕麦

使用上述关键字,我希望返回前两个结果,而不是后两个:

Product1: chocolate, sugar

Product2: chocolate

Product3: chocolate, sugar, milk, oats, bran

Product4: chocolate, sugar, salt

我的专栏包含用逗号分隔的适用于该产品行的所有关键字的列表.

解决方法:

由于您将列表存储为包含逗号分隔列表的字符串,而不是作为一个集合存储,因此MySQL对此将无济于事.当将其插入数据库时​​,MySQL将其视为单个字符串.从数据库中检索它时,MySQL会将其视为单个字符串.当我们在查询中引用它时,MySQL会将其视为单个字符串.

如果将“列表”存储为标准关系集,而将产品的每个关键字存储在表中的单独行中,则返回指定的结果集几乎是微不足道的.

例如,如果我们有此表:

CREATE TABLE product_keyword

product_id BIGINT UNSIGNED COMMENT 'FK ref products.id'

keyword VARCHAR(20)

将与特定产品相关联的每个关键字作为单独的行:

product_id keyword

---------- ---------

1 chocolate

1 sugar

2 chocolate

3 bran

3 chocolate

3 milk

3 oats

3 sugar

4 chocolate

4 salt

4 sugar

然后查找产品中所有关键字不是“巧克力”或“香草”的行

SELECT p.id

FROM product p

JOIN product_keyword k

WHERE k.product_id = p.id

ON k.keyword NOT IN ('chocolate','vanilla')

GROUP BY p.id

– 要么 –

SELECT p.id

FROM product p

LEFT

JOIN ( SELECT j.id

FROM product_keyword j

WHERE j.keyword NOT IN ('chocolate','vanilla')

GROUP BY j.id

) k

ON k.id = p.id

WHERE k.id IS NULL

要获得具有至少一个关键字“ chocolate”和“ vanilla”但没有其他关键字相关联的产品,与上面的查询相同,但具有附加的联接:

SELECT p.id

FROM product p

JOIN ( SELECT g.id

FROM product_keyword g

WHERE g.keyword IN ('chocolate','vanilla')

GROUP BY g.id

) h

ON h.id = p.id

LEFT

JOIN ( SELECT j.id

FROM product_keyword j

WHERE j.keyword NOT IN ('chocolate','vanilla')

GROUP BY j.id

) k

ON k.id = p.id

WHERE k.id IS NULL

我们可以解压缩那些查询,它们并不难.查询h返回具有至少一个关键字的product_id列表,查询k返回具有除指定的关键字以外的某些关键字的product_id列表.此处的“技巧”(如果您要称呼它)是反联接模式……进行外部联接以匹配行,并包括不匹配的行,以及WHERE子句中的谓词,消除具有匹配项的行,从而保留产品中不具有匹配项的行集.

但是将集合存储为单个字符列中的“逗号分隔列表”时,我们将失去关系代数的所有优势;没有简单的方法将关键字列表作为“集合”进行处理.

将整个列表存储为单个字符串,我们得到了一些可怕的SQL来获得指定的结果.

进行指定检查的一种方法是创建一组所有可能的“匹配项”,然后进行检查.这对于几个关键字是可行的.例如,要获取仅具有关键字“香草”和/或“巧克力”的产品列表(即,至少具有其中一个关键字而没有任何其他关键字):

SELECT p.id

FROM product

WHERE keyword_list = 'chocolate'

OR keyword_list = 'vanilla'

OR keyword_list = 'chocolate,vanilla'

OR keyword_list = 'vanilla,chocolate'

但是很快将其扩展到三个,四个或五个关键字就变得很笨拙(除非确保保证关键字以特定的顺序出现.而且要检查四个关键字中的三个关键字非常困难.

另一种(丑陋的)方法是将keyword_list转换为一个集合,以便我们可以像回答中的第一个查询那样使用查询.但是执行转换的SQL受可以从keyword_list提取的任意最大关键字数限制.

使用一些简单的SQL字符串函数从逗号分隔列表中提取第n个元素非常容易,例如,从逗号分隔列表中提取前五个元素:

SET @l := 'chocolate,sugar,bran,oats'

SELECT NULLIF(SUBSTRING_INDEX(CONCAT(@l,','),',',1),'') AS kw1

, NULLIF(SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(@l,','),',',2),',',-1),'') AS kw2

, NULLIF(SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(@l,','),',',3),',',-1),'') AS kw3

, NULLIF(SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(@l,','),',',4),',',-1),'') AS kw4

, NULLIF(SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(@l,','),',',5),',',-1),'') AS kw5

但是那些仍然在同一行.如果要对它们进行检查,则需要做一些比较,我们需要检查每个检查以查看是否在指定列表中.

如果我们可以将这些关键字在一行上转换为一组行,并且每一行上都有一个关键字,那么我们可以使用像第一个查询这样的查询.举个例子:

SELECT t.product_id

, NULLIF(CASE n.i

WHEN 1 THEN SUBSTRING_INDEX(CONCAT(t.l,','),',',1)

WHEN 2 THEN SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(t.l,','),',',2),',',-1)

WHEN 3 THEN SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(t.l,','),',',3),',',-1)

WHEN 4 THEN SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(t.l,','),',',4),',',-1)

WHEN 5 THEN SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(t.l,','),',',5),',',-1)

END,'') AS kw

FROM ( SELECT 4 AS product_id,'fee,fi,fo,fum' AS l

UNION ALL

SELECT 5, 'coffee,sugar,milk'

) t

CROSS

JOIN ( SELECT 1 AS i

UNION ALL SELECT 2

UNION ALL SELECT 3

UNION ALL SELECT 4

UNION ALL SELECT 5

) n

HAVING kw IS NOT NULL

ORDER BY t.product_id, n.i

这使我们获得了单独的行,但是前五个关键字中的每个关键字都限于一行.很容易看出将如何扩展(n返回6,7,8,…)并扩展CASE中的WHEN条件以处理6,7,8 …

但是会有一些任意的限制. (作为演示,我使用了一个别名为t的内联视图来返回两个“示例”行.该内联视图可以替换为对包含product_id和keyword_list列的表的引用.)

因此,该查询使我们获得了一个行集,就像从上面作为示例给出的product_keyword表中返回的那样.

在示例查询中,对product_keyword表的引用可以用该查询替换.但这是很多丑陋的SQL,而且效率极低,在运行查询时都会创建并填充临时MyISAM表.

标签:mysql-workbench,rows,sql,mysql

来源: https://codeday.me/bug/20191121/2055291.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值