我正在使用PostgreSql 9.我有一个简单的问题。 哪个查询更有效?
SELECT users_sessions.session_id, users_sessions.series
FROM users_sessions
WHERE users_sessions.user_id = 8
AND users_sessions.session_id IN (
SELECT session_id
FROM sessions_history
GROUP BY sessions_history.session_id
HAVING SUM(CASE WHEN sessions_history.action = 2 THEN 1 END) = 0
)
VS
SELECT US8.session_id,Us8.series
FROM
( SELECT us.session_id as S_ID, us.series
FROM users_sessions as US
WHERE US.user_id = 8 ) AS US8
INNER JOIN
(SELECT SH.session_id as SH_ID
FROM session_history as SH
WHERE SH.action <> 2) AS SH2
ON US8.session_id = SH2.session_id
答案 0 :(得分:1)
您的第二个查询 在语法上无效。您无法在SELECT
子句中的HAVING
列表(&#34;输出列&#34;)中引用列别名。
无论哪种方式,两个查询都不好。如果您确实想要找到不存在的(user_id, action)
组合,请尝试改为:
SELECT t.*, 0 AS s
FROM (SELECT 8 AS user_id, 2 AS action) t
LEFT JOIN (
users_sessions us
JOIN session_history sh USING (session_id)
) USING (user_id, action)
WHERE sh.session_id IS NULL;
我将子查询t
和LEFT JOIN
中的单行的派生表引入到两个基表的组合中。如果组合不,则仅返回一行。
假设列名user_id
和action
在两个表中只出现一次。否则,对第二个连接使用更明确的条件:
ON t.user_id = us.user_id AND t.action = sh.action
详细说明:
可能更快,但是:
SELECT t.*, 0 AS s
FROM (SELECT 8 AS user_id, 2 AS action) t
LEFT JOIN users_sessions us USING (user_id)
LEFT JOIN session_history sh USING (action, session_id)
WHERE sh.session_id IS NULL;
在此示例中,USING
构造是安全的。
答案 1 :(得分:1)
另一种解决方案使用NOT EXISTS,它是您似乎要求的精确翻译:
给我没有行动2的会议:
SELECT session_id, series
FROM users_sessions as us
WHERE users_sessions.user_id = 8
AND NOT EXISTS
( SELECT *
FROM sessions_history as sh
WHERE action = 2
AND us.session_id = sh.session_id
)
答案 2 :(得分:1)
我的值得一提;
我可以用两种不同的方式解释你的意图,并为每个提供不同的解决方案(我的首选解决方案在每种情况下都是第一个);
至少有一条历史记录的会话,其中的操作&lt;&gt; 2 强>
(而不关心有多少历史记录,其中action = 2)
SELECT
us.session_id,
us.series
FROM
users_sessions AS us
INNER JOIN
session_history AS sh
ON sh.session_id = us.session_id
AND sh.action <> 2
WHERE
us.user_id = 8
GROUP BY
us.session_id,
us.series
或
SELECT
us.session_id,
us.series
FROM
users_sessions AS us
WHERE
us.user_id = 8
AND EXISTS (SELECT *
FROM session_history AS sh
WHERE sh.session_id = us.session_id
AND sh.action <> 2
)
或
SELECT
us.session_id,
us.series
FROM
users_sessions AS us
INNER JOIN
(
SELECT
session_id
FROM
session_history
WHERE
sh.action <> 2
GROUP BY
session_id
)
AS sh
ON sh.session_id = us.session_id
WHERE
us.user_id = 8
没有历史记录的会话记录where action = 2
(但可以有其他历史记录)
SELECT
us.session_id,
us.series
FROM
users_sessions AS us
LEFT JOIN
session_history AS sh
ON sh.session_id = us.session_id
AND sh.action = 2
WHERE
us.user_id = 8
AND sh.session_id IS NULL
-- No GROUP BY needed this time
或
SELECT
us.session_id,
us.series
FROM
users_sessions AS us
WHERE
us.user_id = 8
AND NOT EXISTS (SELECT *
FROM session_history AS sh
WHERE sh.session_id = us.session_id
AND sh.action = 2
)
答案 3 :(得分:0)
您如何看待这个?
SELECT US8.session_id,Us8.series
FROM
( SELECT us.session_id as S_ID, us.series
FROM users_sessions as US
WHERE US.user_id = 8 ) AS US8
INNER JOIN
(SELECT SH.session_id as SH_ID
FROM session_history as SH
WHERE SH.action <> 2) AS SH2
ON US8.session_id = SH2.session_id