分割字符串后在标签之间搜索标签

问题描述 投票:0回答:1

我正在使用 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

sqlite
1个回答
0
投票

您可以将

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)
;

结果:-

  • Result
  • 注意最后的 SELECT 与
    WHERE pcode <> 'q200'
    'cc' IN (SELECT ....
  • LIMIT 100 可能需要更改为更合适的值(或者甚至可以删除)

CTE(执行临时表)有以下数据:-

  • Intermediate
  • 可以看出,标签被提取到current_tag列中,remaining_tags列
    • 注意每个 tblproduct 行的初始空 current_tag 如何在
      IN
      子句中排除。

演示 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;
© www.soinside.com 2019 - 2024. All rights reserved.