在 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
没有意义。
至于日期范围,看你要不要查:
event
和 reg
而不是 guest
值仅在该范围内;或
- 任何
event
和 reg
而不是 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 C2
和 C4
行,后者查询 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'
)
我正在使用 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
没有意义。
至于日期范围,看你要不要查:
event
和reg
而不是guest
值仅在该范围内;或- 任何
event
和reg
而不是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 C2
和 C4
行,后者查询 returns 仅 C2
行(作为 reg
C4
的值存在,但不在日期范围内)。
db<>fiddle here
I want join the column
MAIL_ID
from another tablecst_mail
using joins. to refer the correspondingmaild id
for thecust_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'
)