在 SQL 中比 AND 运算符更有效的查询

Effective query than AND operator in SQL

我正在使用 Oracle 数据库。以下查询未按预期工作。

select * 
from cst_cust_attributes 
where attribute_value='event' 
and attribute_value='reg'
and attribute_value != 'guest';

我需要 'event' 和 'reg' 中只有 attribute_values 而 'guest' 中没有的所有客户数据。但我得到了正确的输出。记录由拥有所有 3 attribute_values.

的客户数据混合而成

下面是table

的结构
Name            Null?    Type          
--------------- -------- ------------- 
ORGANIZATION_ID NOT NULL NUMBER(19)    
CUST_ID         NOT NULL VARCHAR2(32)  
ATTRIBUTE_ID    NOT NULL NUMBER(19)    
ATTRIBUTE_SEQ   NOT NULL NUMBER(10)    
ATTRIBUTE_VALUE NOT NULL VARCHAR2(254) 
ACTIVE_FLAG     NOT NULL NUMBER(3)     
CREATE_DATE              DATE          
CREATE_USER              VARCHAR2(254) 
UPDATE_DATE              DATE          
UPDATE_USER              VARCHAR2(254) 

所以您基本上只想 attribute_value 成为“事件”和“注册”? 那么为什么不使用下面的 select ?

select * from cst_cust_attributes where attribute_value in('event','reg');

您可以使用 COUNT 分析函数和条件聚合:

SELECT *
FROM   (
  SELECT a.*,
         COUNT(CASE attribute_value WHEN 'event' THEN 1 END)
           OVER (PARTITION BY cust_id) AS num_event,
         COUNT(CASE attribute_value WHEN 'reg' THEN 1 END)
           OVER (PARTITION BY cust_id) AS num_reg,
         COUNT(CASE attribute_value WHEN 'guest' THEN 1 END)
           OVER (PARTITION BY cust_id) AS num_guest 
  FROM   cst_cust_attributes a
)
WHERE  num_event > 0
AND    num_reg   > 0
AND    num_guest = 0;

其中,对于示例数据:

INSERT INTO cst_cust_attributes (
  organization_id,
  cust_id,
  attribute_id,
  attribute_seq,
  attribute_value,
  active_flag
)
SELECT 1, 'C1', 1, 1, 'event', 1 FROM DUAL UNION ALL
SELECT 1, 'C1', 2, 1, 'reg',   1 FROM DUAL UNION ALL
SELECT 1, 'C1', 3, 1, 'guest', 1 FROM DUAL UNION ALL
SELECT 1, 'C2', 1, 1, 'event', 1 FROM DUAL UNION ALL
SELECT 1, 'C2', 2, 1, 'reg',   1 FROM DUAL UNION ALL
SELECT 1, 'C3', 1, 1, 'event', 1 FROM DUAL;

输出:

ORGANIZATION_ID CUST_ID ATTRIBUTE_ID ATTRIBUTE_SEQ ATTRIBUTE_VALUE ACTIVE_FLAG CREATE_DATE CREATE_USER UPDATE_DATE UPDATE_USER NUM_EVENT NUM_REG NUM_GUEST
1 C2 1 1 event 1 NULL NULL NULL NULL 1 1 0
1 C2 2 1 reg 1 NULL NULL NULL NULL 1 1 0

could you please tell me where to add the below condition and trunc(CREATE_DATE) >='05-MAY-2019' AND trunc(CREATE_DATE)<='13-APR-2022' group by cust_id;

如果您尝试 return 所有行,添加 GROUP BY 没有意义。

至于日期范围,看你要不要查:

  • eventreg 而不是 guest 值仅在该范围内;或
  • 任何 eventreg 而不是 guest 行存在,无论是在该日期范围内还是在该日期范围外,然后 return 该范围内的行。

对于前者,您可以在 sub-query:

中添加一个 WHERE 子句
SELECT *
FROM   (
  SELECT a.*,
         COUNT(CASE attribute_value WHEN 'event' THEN 1 END)
           OVER (PARTITION BY cust_id) AS num_event,
         COUNT(CASE attribute_value WHEN 'reg' THEN 1 END)
           OVER (PARTITION BY cust_id) AS num_reg,
         COUNT(CASE attribute_value WHEN 'guest' THEN 1 END)
           OVER (PARTITION BY cust_id) AS num_guest 
  FROM   cst_cust_attributes a
  WHERE  create_date >= DATE '2019-05-05'
  AND    create_date <  DATE '2022-04-13' + INTERVAL '1' DAY
)
WHERE  num_event > 0
AND    num_reg   > 0
AND    num_guest = 0;

对于后者,过滤器将添加到外部查询:

SELECT *
FROM   (
  SELECT a.*,
         COUNT(CASE attribute_value WHEN 'event' THEN 1 END)
           OVER (PARTITION BY cust_id) AS num_event,
         COUNT(CASE attribute_value WHEN 'reg' THEN 1 END)
           OVER (PARTITION BY cust_id) AS num_reg,
         COUNT(CASE attribute_value WHEN 'guest' THEN 1 END)
           OVER (PARTITION BY cust_id) AS num_guest 
  FROM   cst_cust_attributes a
)
WHERE  num_event > 0
AND    num_reg   > 0
AND    num_guest = 0
AND    create_date >= DATE '2019-05-05'
AND    create_date <  DATE '2022-04-13' + INTERVAL '1' DAY;

其中,对于示例数据:

INSERT INTO cst_cust_attributes (
  organization_id,
  cust_id,
  attribute_id,
  attribute_seq,
  attribute_value,
  active_flag,
  create_date
)
SELECT 1, 'C1', 1, 1, 'event', 1, DATE '2022-01-01' FROM DUAL UNION ALL
SELECT 1, 'C1', 2, 1, 'reg',   1, DATE '2022-01-01' FROM DUAL UNION ALL
SELECT 1, 'C1', 3, 1, 'guest', 1, DATE '2022-01-01' FROM DUAL UNION ALL
SELECT 1, 'C2', 1, 1, 'event', 1, DATE '2022-01-01' FROM DUAL UNION ALL
SELECT 1, 'C2', 2, 1, 'reg',   1, DATE '2022-01-01' FROM DUAL UNION ALL
SELECT 1, 'C3', 1, 1, 'event', 1, DATE '2022-01-01' FROM DUAL UNION ALL
SELECT 1, 'C4', 1, 1, 'event', 1, DATE '2022-01-01' FROM DUAL UNION ALL
SELECT 1, 'C4', 2, 1, 'reg',   1, DATE '2022-01-01' FROM DUAL UNION ALL
SELECT 1, 'C4', 3, 1, 'guest', 1, DATE '2018-01-01' FROM DUAL;

然后前者查询 returns C2C4 行,后者查询 returns 仅 C2 行(作为 reg C4 的值存在,但不在日期范围内)。

db<>fiddle here


I want join the column MAIL_ID from another table cst_mail using joins. to refer the corresponding maild id for the cust_id

类似于:

SELECT a.*,
       m.mail_id
FROM   (
         SELECT a.*,
                COUNT(CASE attribute_value WHEN 'event' THEN 1 END)
                  OVER (PARTITION BY cust_id) AS num_event,
                COUNT(CASE attribute_value WHEN 'reg' THEN 1 END)
                  OVER (PARTITION BY cust_id) AS num_reg,
                COUNT(CASE attribute_value WHEN 'guest' THEN 1 END)
                  OVER (PARTITION BY cust_id) AS num_guest 
         FROM   cst_cust_attributes a
         WHERE  create_date >= DATE '2019-05-05'
         AND    create_date <  DATE '2022-04-13' + INTERVAL '1' DAY
       ) a
       JOIN cst_mail m
       ON (a.cust_id = m.cust_id)
WHERE  num_event > 0
AND    num_reg   > 0
AND    num_guest = 0;

您需要使用类似下面的查询来检查所有条件

select * 
from cst_cust_attributes c
left join cst_mail n on c.CUST_ID   =n.CUST_ID   
where c.attribute_value='event' 
and exists 
( 
select 1 from cst_cust_attributes b where c.CUST_ID   = b.CUST_ID  
and b.attribute_value='reg'
)
and not exists
(
select 1 from cst_cust_attributes a where c.CUST_ID   = a.CUST_ID  
and a.attribute_value = 'guest'
)