SQL Oracle获取与值列表完全匹配的行

lc8prwob  于 2022-12-03  发布在  Oracle
关注(0)|答案(2)|浏览(112)

我有一个表,我需要得到与值列表匹配的行。我创建了一个SQLFiddle,你可以在那里看到结果。
此查询用于填充使用或不使用自动完成的DropDownList。因此,此请求有两种可能的用途:第一个是空的LIKE('%'),第二个是填充的LIKE('***%')。只有第一个用法有问题,因为所有行都是在没有LIKE条件的情况下选择的,我只需要那些与PGM列的值列表匹配的行。
我的问题是,我无法获得PGM = 'N'和'L'的行(根据Fiddle示例),而不仅仅是'L'或'N',也不是'L'和'N'和'P':如果这是列表中的值,则仅对“N”和“L”。

SELECT al.* FROM ALPHA al WHERE al.PN IN (
    SELECT al2.PN FROM ALPHA al2 WHERE TRIM(al2.PGM) IN ('N','L') AND TRIM(al2.NUM) IN ('2350') AND TRIM(al2.TEAM) = 'R2D2' 
    AND TRIM(al2.PN) LIKE '%' AND (
      SELECT COUNT(*) FROM ALPHA al3 WHERE TRIM(al3.PGM) IN ('N','L') AND TRIM(al3.PN) LIKE '%') = 2
)
AND TRIM(al.PGM) IN ('N','L') ORDER BY al.PN ASC;

/*
The idea, in a nutshell, is as follows:
line 1 - Get all rows from ALPHA
line 2 - Get filtered rows from ALPHA according to PGM, NUM, TEAM
line 3 - Filter PN with LIKE (according to autocompletion or not)
line 4 - Get rows which have a PGM = N and PGM = L ONLY | As there are two values in the list it should returns 2 but it does not because of empty LIKE
line 6 - Filter all rows according to PGM
*/

我知道这个link,但我不能在我的情况下使用它,在PROD中,我正在处理VIEW not joined TABLES。
谢谢你,谢谢你

svmlkihl

svmlkihl1#

您似乎只想获取这样的行,其中存在一个N,并且每个PN都有一个L,并且这些N也与筛选器匹配;在这种情况下,使用带有条件聚合解析COUNT函数:

SELECT sms, pgm, pn, team, num
FROM   (
  SELECT a.*,
         COUNT(CASE PGM WHEN 'N' THEN 1 END) OVER (PARTITION BY PN) AS cnt_n,
         COUNT(CASE PGM WHEN 'L' THEN 1 END) OVER (PARTITION BY PN) AS cnt_l,
         COUNT(CASE WHEN PGM IN ('L', 'N') THEN NULL ELSE 1 END) OVER (PARTITION BY PN) AS cnt_other
  FROM   ALPHA a
  WHERE  PN   LIKE 'BB%'
  AND    NUM  = '2350'
  AND    TEAM = 'R2D2'
)
WHERE cnt_l > 0
AND   cnt_n > 0
AND   cnt_other = 0
ORDER BY PN ASC;

小提琴
如果有动态列表,则可以创建集合数据类型:

CREATE TYPE char_list IS TABLE OF CHAR(1);

然后使用查询:

SELECT sms, pgm, pn, team, num
FROM   (
  SELECT a.*,
         COUNT(
           DISTINCT
           CASE WHEN PGM MEMBER OF char_list('N', 'L') THEN PGM END
         ) OVER (PARTITION BY PN) AS cnt_match,
         COUNT(
           CASE WHEN PGM NOT MEMBER OF char_list('N', 'L') THEN 1 END
         ) OVER (PARTITION BY PN) AS cnt_other
  FROM   ALPHA a
  WHERE  PN   LIKE 'BB%'
  AND    NUM  = '2350'
  AND    TEAM = 'R2D2'
)
WHERE cnt_match = CARDINALITY( char_list('N', 'L') )
AND   cnt_other = 0
ORDER BY PN ASC;

并且,如果您使用的客户端支持它(Java支持),您可以将数组作为绑定变量传递给集合:

SELECT sms, pgm, pn, team, num
FROM   (
  SELECT a.*,
         COUNT(
           DISTINCT
           CASE WHEN PGM MEMBER OF :your_list THEN PGM END
         ) OVER (PARTITION BY PN) AS cnt_match,
         COUNT(
           CASE WHEN PGM NOT MEMBER OF :your_list THEN 1 END
         ) OVER (PARTITION BY PN) AS cnt_other
  FROM   ALPHA a
  WHERE  PN   LIKE 'BB%'
  AND    NUM  = '2350'
  AND    TEAM = 'R2D2'
)
WHERE cnt_match = CARDINALITY( :your_list )
AND   cnt_other = 0
ORDER BY PN ASC;

如果您不想使用集合,则:

WITH match_values (value) AS (
  SELECT 'N' FROM DUAL UNION ALL
  SELECT 'L' FROM DUAL
)
SELECT sms, pgm, pn, team, num
FROM   (
  SELECT a.*,
         COUNT(
           DISTINCT
           CASE WHEN PGM IN (SELECT value FROM match_values) THEN PGM END
         ) OVER (PARTITION BY PN) AS cnt_match,
         COUNT(
           CASE WHEN PGM NOT IN (SELECT value FROM match_values) THEN 1 END
         ) OVER (PARTITION BY PN) AS cnt_other
  FROM   ALPHA a
  WHERE  PN   LIKE 'BB%'
  AND    NUM  = '2350'
  AND    TEAM = 'R2D2'
)
WHERE cnt_match = (SELECT COUNT(*) FROM match_values)
AND   cnt_other = 0
ORDER BY PN ASC;

fiddle

pbossiut

pbossiut2#

您可以创建CTE(pgm_filter)并在以后在WHERE子句中使用它.

WITH
    pgm_filter AS
        (
            Select   PN, PGM_LIST
            From     (SELECT DISTINCT PN, PGM, LISTAGG(PGM, '') WITHIN GROUP (Order By PGM) OVER(PARTITION BY PN) "PGM_LIST"
                      FROM   ALPHA a)
            Where    PGM_LIST  = 'LN'
            Group By PN, PGM_LIST      
        )

LISTAGG()分析函数用于生成每个PN的PGM值列表。其中,条件仅筛选具有值'L'和'N'的特定组合的PN-不多不少。
WHERE子句中包含pgm_filter的主SQL:

SELECT    SMS, PGM, PN, TEAM, NUM
FROM      ALPHA
WHERE     PN IN(Select PN From pgm_filter) And
          PN   LIKE 'PP%' And
          NUM  = '2350' And
          TEAM = 'R2D2'

...这将过滤具有PGM值的'LN'组合的行沿着您需要的任何其他过滤器。
此致

相关问题