我正在使用 SQLite 和 PDO 来运行一些 SQL 命令。
表字段和数据:
ID title tag pcode
----------------------------------------
1 title1 aa,bb,cc,dd a100
2 title2 cc,ee,dd,ba b250
3 title3 dd,ff,gr,ax br10
4 title4 cc,dd,aa,fx q200
5 title5 xx,ad,fr,aa ar50
我只想用
,
字符分隔当前字段标签值,然后在标签字段中存在的所有标签之间进行搜索,除了当前 pcode
值
举个例子:我想找到所有标签,如
cc
或 dd
或 aa
或 fx
与当前记录,以及当当前 pcode
是 q200
时,标签内容 cc,dd,aa,fx
除了 pcode q200
我确实尝试过这个:
select title,pcode from tblproduct WHERE (tag like '%cc%') and (pcode <> 'q200')
它可以工作,但是我如何更改它以查找当前标签中的所有值,意思是:
搜索
cc
,然后搜索 dd
,然后搜索 aa
,然后在表中除 fx
之外的所有标签中搜索 pcode
值,并使用 q200
您可以将
IN
子句与递归 CTE 结合使用,将标签拆分为单独的标签,例如:-
WITH
/* CTE (Common Table Expression)
splits the tag into individual tags with an output row per each tag/tblproduct row combination
*/
cte_split AS (
/* Initial row (per row in tblproduct) */
SELECT
id,title,pcode, /* only really need the id column*/
'' AS current_tag,
tag||',' AS remaining_tags /* NOTE the addition of the trailing comma so instr works on last tag*/
FROM tblproduct
/* recursively strip of the current tag and prepare the remaining_tags for the next */
UNION ALL select
id,title,pcode, /* copy the original columns */
/* get the currrent tag*/
substr(remaining_tags,1,instr(remaining_tags,',')-1) AS current_tag,
substr(remaining_tags,instr(remaining_tags,',')+1) AS remaining_tags
FROM cte_split
WHERE length(remaining_tags) > 0 /* this should determine when the recursion stops */
LIMIT 100 /* just in case limit the number of recursions */
)
/* Now the cte can be used for an IN */
/* !!!!NOTE!!!! IN is an exact so LIKE not usable */
SELECT * FROM tblproduct
WHERE pcode <> 'q200'
AND 'cc' IN (SELECT (current_tag) FROM cte_split WHERE cte_split.id = tblproduct.id AND length(current_tag) > 0)
;
结果:-
CTE(执行临时表)有以下数据:-
演示 SQL
以下 SQL 用于生成上述答案:-
DROP TABLE IF EXISTS tblproduct;
/*
ID title tag pcode
----------------------------------------
1 title1 aa,bb,cc,dd a100
2 title2 cc,ee,dd,ba b250
3 title3 dd,ff,gr,ax br10
4 title4 cc,dd,aa,fx q200
5 title5 xx,ad,fr,aa ar50
*/
CREATE TABLE IF NOT EXISTS tblproduct (id INTEGER PRIMARY KEY, title TEXT, tag TEXT, pcode TEXT);
INSERT OR IGNORE INTO tblproduct VALUES
(1,'title1','aa,bb,cc,dd','a100'),
(2,'title2','cc,ee,dd,ba','b250'),
(3,'title3','dd,ff,gr,ax','br10'),
(4,'title4','cc,dd,aa,fx','q200'),
(5,'title5','xx,ad,fr,aa','ar50')
;
/* DEMO of the CTE table (i.e. just drives )*/
WITH
/* CTE (Common Table Expression)
splits the tag into individual tags with an output row per each tag/tblproduct row combination
*/
cte_split AS (
/* Initial row (per row in tblproduct) */
SELECT
id,title,pcode, /* only really need the id column*/
'' AS current_tag,
tag||',' AS remaining_tags /* NOTE the addition of the trailing comma so instr works on last tag*/
FROM tblproduct
/* recursively strip of the current tag and prepare the remaining_tags for the next */
UNION ALL select
id,title,pcode, /* copy the original columns */
/* get the currrent tag*/
substr(remaining_tags,1,instr(remaining_tags,',')-1) AS current_tag,
substr(remaining_tags,instr(remaining_tags,',')+1) AS remaining_tags
FROM cte_split
WHERE length(remaining_tags) > 0 /* this should determing when the recursion stops */
LIMIT 100 /* just in case limit the number of recursions */
)
/* Now the cte can be used for an IN */
/* !!!!NOTE!!!! IN is an exact so LIKE not usable */
SELECT * FROM cte_split
;
WITH
/* CTE (Common Table Expression)
splits the tag into individual tags with an output row per each tag/tblproduct row combination
*/
cte_split AS (
/* Initial row (per row in tblproduct) */
SELECT
id,title,pcode, /* only really need the id column*/
'' AS current_tag,
tag||',' AS remaining_tags /* NOTE the addition of the trailing comma so instr works on last tag*/
FROM tblproduct
/* recursively strip of the current tag and prepare the remaining_tags for the next */
UNION ALL select
id,title,pcode, /* copy the original columns */
/* get the currrent tag*/
substr(remaining_tags,1,instr(remaining_tags,',')-1) AS current_tag,
substr(remaining_tags,instr(remaining_tags,',')+1) AS remaining_tags
FROM cte_split
WHERE length(remaining_tags) > 0 /* this should determing when the recursion stops */
LIMIT 100 /* just in case limit the number of recursions */
)
/* Now the cte can be used for an IN */
/* !!!!NOTE!!!! IN is an exact so LIKE not usable */
SELECT * FROM tblproduct
WHERE pcode <> 'q200'
AND 'cc' IN (SELECT (current_tag) FROM cte_split WHERE cte_split.id = tblproduct.id AND length(current_tag) > 0)
;
DROP TABLE IF EXISTS tblproduct;