如何一次从三个表中 return 行?
How to return rows from three tables at once?
如何将这三个查询合并为一个?
1.
SELECT "Skills"."name", "Skills"."id", "TrainerScores"."fellow_uid", MIN("TrainerScores"."score") AS "score"
FROM "TrainerScores"
INNER JOIN "Skills" ON "TrainerScores"."skill_id" = "Skills"."id"
WHERE "TrainerScores"."fellow_uid" = 'google:105697533513134511631'
AND DATE("TrainerScores"."created_at") BETWEEN '2015-10-01' AND '2015-10-30'
GROUP BY "Skills"."name", "Skills"."id", "TrainerScores"."fellow_uid"
2.
Select "Skills"."name", "Skills"."id", MIN("PeerScores"."score") AS "score"
FROM "PeerScores"
LEFT OUTER JOIN "Skills" ON "PeerScores"."skill_id" = "Skills"."id"
WHERE "PeerScores"."evaluatee_uid" = 'google:105697533513134511631'
AND DATE("PeerScores"."created_at") BETWEEN '2015-10-01' AND '2015-10-30'
GROUP BY "Skills"."name", "Skills"."id"
3.
Select "Skills"."name", "Skills"."id", MIN("SelfScores"."score") AS "score"
FROM "SelfScores"
LEFT OUTER JOIN "Skills" ON "SelfScores"."skill_id" = "Skills"."id"
WHERE "SelfScores"."fellow_uid" = 'google:105697533513134511631'
AND DATE("SelfScores"."created_at") BETWEEN '2015-10-01' AND '2015-10-30'
GROUP BY "Skills"."name", "Skills"."id"
我想将其用作报告,我不想在任何时候想要获取数据时调用每个查询。
我提出了一个完全符合您要求的解决方案,但它确实有效。使用 raw 查询,您可以 运行 并获得多个查询的结果,如下所示:
var sequelize = require('./libs/pg_db_connect');
var query = "SELECT Skills.name, Skills.id, TrainerScores.fellow_uid, MIN(TrainerScores.score) AS score
FROM TrainerScores
INNER JOIN Skills ON TrainerScores.skill_id = Skills.id
WHERE TrainerScores.fellow_uid = 'google:105697533513134511631' AND DATE(TrainerScores.created_at) BETWEEN '2015-10-01' AND '2015-10-30'
GROUP BY Skills.name, Skills.id, TrainerScores.fellow_uid";
sequelize.query(query, {
type: sequelize.QueryTypes.SELECT
}).success(function (query1) {
done = _.after(query1.length, function () {
callback(query1)
})
query = "Select Skills.name, Skills.id, MIN(PeerScores.score) AS score
FROM PeerScores
LEFT OUTER JOIN Skills ON PeerScores.skill_id = Skills.id
WHERE PeerScores.evaluatee_uid = 'google:105697533513134511631' AND DATE(PeerScores.created_at) BETWEEN '2015-10-01' AND '2015-10-30'
GROUP BY Skills.name, Skills.id";
sequelize.query(query, {
type: sequelize.QueryTypes.SELECT
}).success(function (query2) {
query = "Select Skills.name, Skills.id, MIN(SelfScores.score) AS score
FROM SelfScores
LEFT OUTER JOIN Skills ON SelfScores.skill_id = Skills.id
WHERE SelfScores.fellow_uid = 'google:105697533513134511631' AND DATE(SelfScores.created_at) BETWEEN '2015-10-01' AND '2015-10-30'
GROUP BY Skills.name, Skills.id";
sequelize.query(query, {
type: sequelize.QueryTypes.SELECT
}).success(function (query3) {
console.log(query1); // show the returns of query 1
console.log(query2); // show the returns of query 2
console.log(query3); // show the returns of query 3
});
success
函数的结果sequelize.query
也可以存储在json变量中。
备选方案 1,只是一个巨大的 UNION ALL
:
SELECT "Skills"."name", "Skills"."id", "TrainerScores"."fellow_uid", MIN("TrainerScores"."score") AS "score"
FROM "TrainerScores"
INNER JOIN "Skills" ON "TrainerScores"."skill_id" = "Skills"."id"
WHERE "TrainerScores"."fellow_uid" = 'google:105697533513134511631'
AND DATE("TrainerScores"."created_at") BETWEEN '2015-10-01' AND '2015-10-30'
GROUP BY "Skills"."name", "Skills"."id", "TrainerScores"."fellow_uid"
UNION ALL
Select "Skills"."name", "Skills"."id", NULL, MIN("PeerScores"."score") AS "score"
FROM "PeerScores"
LEFT OUTER JOIN "Skills" ON "PeerScores"."skill_id" = "Skills"."id"
WHERE "PeerScores"."evaluatee_uid" = 'google:105697533513134511631'
AND DATE("PeerScores"."created_at") BETWEEN '2015-10-01' AND '2015-10-30'
GROUP BY "Skills"."name", "Skills"."id"
UNION ALL
Select "Skills"."name", "Skills"."id", NULL, MIN("SelfScores"."score") AS "score"
FROM "SelfScores"
LEFT OUTER JOIN "Skills" ON "SelfScores"."skill_id" = "Skills"."id"
WHERE "SelfScores"."fellow_uid" = 'google:105697533513134511631'
AND DATE("SelfScores"."created_at") BETWEEN '2015-10-01' AND '2015-10-30'
GROUP BY "Skills"."name", "Skills"."id"
基本上,像 一样使用 UNION ALL
。
"Combining Queries".
章节中手册中的详细信息
但是还有 很多。我有根据的猜测,你真的想要这个:
WITH vals AS (SELECT timestamp '2015-10-01 00:00' AS ts_low -- incl. lower bound
, timestamp '2015-10-31 00:00' AS ts_hi -- excl. upper bound
, text 'google:105697533513134511631' AS uid)
SELECT s.name, sub.*
FROM (
SELECT skill_id AS id, min(score) AS score, 'T' AS source
FROM "TrainerScores", vals v
WHERE fellow_uid = v.uid
AND created_at >= v.ts_low
AND created_at < v.ts_hi
GROUP BY 1
UNION ALL
SELECT skill_id, min(score), 'P'
FROM "PeerScores", vals v
WHERE evaluatee_uid = v.uid
AND created_at >= v.ts_low
AND created_at < v.ts_hi
GROUP BY 1
UNION ALL
SELECT skill_id, min(score), 'S'
FROM "SelfScores", vals v
WHERE fellow_uid = v.uid
AND created_at >= v.ts_low
AND created_at < v.ts_hi
GROUP BY 1
) sub
JOIN "Skills" s USING (id);
要点
首先,我trim从你的语法(可能由你的 ORM 产生)中消除噪音,使其易于阅读:删除多余的双引号,添加 table 别名,trim 杂词...
您对 LEFT [OUTER] JOIN
的使用被破坏了,因为您过滤了左侧 table 的列,这抵消了 LEFT JOIN
。替换为 [INNER] JOIN
.
在 WHERE
子句中使用 sargable 表达式,否则您的查询不能使用普通索引,并且对于大 tables 会非常慢。相关:
- Get difference of another field between first and last timestamps of grouping
在 CTE(WITH
子句)中 一次 提供您的参数 - 这是不需要的在准备好的语句中,您将 uid
、ts_low
和 ts_hi
作为参数传递。
我从您的第一个查询的输出中删除了 "TrainerScores"."fellow_uid"
以简化查询。无论如何,这只是您的输入参数。
您可以在加入[=21=之前聚合您各自的主要table ] 一次.
我添加了一列 source
来表示每一行的来源。
旁白:您似乎想匹配整个 2015 年 10 月,但随后排除了 10 月 31 日。这是故意的吗?
如何将这三个查询合并为一个?
1.
SELECT "Skills"."name", "Skills"."id", "TrainerScores"."fellow_uid", MIN("TrainerScores"."score") AS "score"
FROM "TrainerScores"
INNER JOIN "Skills" ON "TrainerScores"."skill_id" = "Skills"."id"
WHERE "TrainerScores"."fellow_uid" = 'google:105697533513134511631'
AND DATE("TrainerScores"."created_at") BETWEEN '2015-10-01' AND '2015-10-30'
GROUP BY "Skills"."name", "Skills"."id", "TrainerScores"."fellow_uid"
2.
Select "Skills"."name", "Skills"."id", MIN("PeerScores"."score") AS "score"
FROM "PeerScores"
LEFT OUTER JOIN "Skills" ON "PeerScores"."skill_id" = "Skills"."id"
WHERE "PeerScores"."evaluatee_uid" = 'google:105697533513134511631'
AND DATE("PeerScores"."created_at") BETWEEN '2015-10-01' AND '2015-10-30'
GROUP BY "Skills"."name", "Skills"."id"
3.
Select "Skills"."name", "Skills"."id", MIN("SelfScores"."score") AS "score"
FROM "SelfScores"
LEFT OUTER JOIN "Skills" ON "SelfScores"."skill_id" = "Skills"."id"
WHERE "SelfScores"."fellow_uid" = 'google:105697533513134511631'
AND DATE("SelfScores"."created_at") BETWEEN '2015-10-01' AND '2015-10-30'
GROUP BY "Skills"."name", "Skills"."id"
我想将其用作报告,我不想在任何时候想要获取数据时调用每个查询。
我提出了一个完全符合您要求的解决方案,但它确实有效。使用 raw 查询,您可以 运行 并获得多个查询的结果,如下所示:
var sequelize = require('./libs/pg_db_connect');
var query = "SELECT Skills.name, Skills.id, TrainerScores.fellow_uid, MIN(TrainerScores.score) AS score
FROM TrainerScores
INNER JOIN Skills ON TrainerScores.skill_id = Skills.id
WHERE TrainerScores.fellow_uid = 'google:105697533513134511631' AND DATE(TrainerScores.created_at) BETWEEN '2015-10-01' AND '2015-10-30'
GROUP BY Skills.name, Skills.id, TrainerScores.fellow_uid";
sequelize.query(query, {
type: sequelize.QueryTypes.SELECT
}).success(function (query1) {
done = _.after(query1.length, function () {
callback(query1)
})
query = "Select Skills.name, Skills.id, MIN(PeerScores.score) AS score
FROM PeerScores
LEFT OUTER JOIN Skills ON PeerScores.skill_id = Skills.id
WHERE PeerScores.evaluatee_uid = 'google:105697533513134511631' AND DATE(PeerScores.created_at) BETWEEN '2015-10-01' AND '2015-10-30'
GROUP BY Skills.name, Skills.id";
sequelize.query(query, {
type: sequelize.QueryTypes.SELECT
}).success(function (query2) {
query = "Select Skills.name, Skills.id, MIN(SelfScores.score) AS score
FROM SelfScores
LEFT OUTER JOIN Skills ON SelfScores.skill_id = Skills.id
WHERE SelfScores.fellow_uid = 'google:105697533513134511631' AND DATE(SelfScores.created_at) BETWEEN '2015-10-01' AND '2015-10-30'
GROUP BY Skills.name, Skills.id";
sequelize.query(query, {
type: sequelize.QueryTypes.SELECT
}).success(function (query3) {
console.log(query1); // show the returns of query 1
console.log(query2); // show the returns of query 2
console.log(query3); // show the returns of query 3
});
success
函数的结果sequelize.query
也可以存储在json变量中。
备选方案 1,只是一个巨大的 UNION ALL
:
SELECT "Skills"."name", "Skills"."id", "TrainerScores"."fellow_uid", MIN("TrainerScores"."score") AS "score"
FROM "TrainerScores"
INNER JOIN "Skills" ON "TrainerScores"."skill_id" = "Skills"."id"
WHERE "TrainerScores"."fellow_uid" = 'google:105697533513134511631'
AND DATE("TrainerScores"."created_at") BETWEEN '2015-10-01' AND '2015-10-30'
GROUP BY "Skills"."name", "Skills"."id", "TrainerScores"."fellow_uid"
UNION ALL
Select "Skills"."name", "Skills"."id", NULL, MIN("PeerScores"."score") AS "score"
FROM "PeerScores"
LEFT OUTER JOIN "Skills" ON "PeerScores"."skill_id" = "Skills"."id"
WHERE "PeerScores"."evaluatee_uid" = 'google:105697533513134511631'
AND DATE("PeerScores"."created_at") BETWEEN '2015-10-01' AND '2015-10-30'
GROUP BY "Skills"."name", "Skills"."id"
UNION ALL
Select "Skills"."name", "Skills"."id", NULL, MIN("SelfScores"."score") AS "score"
FROM "SelfScores"
LEFT OUTER JOIN "Skills" ON "SelfScores"."skill_id" = "Skills"."id"
WHERE "SelfScores"."fellow_uid" = 'google:105697533513134511631'
AND DATE("SelfScores"."created_at") BETWEEN '2015-10-01' AND '2015-10-30'
GROUP BY "Skills"."name", "Skills"."id"
基本上,像 UNION ALL
。
"Combining Queries".
但是还有 很多。我有根据的猜测,你真的想要这个:
WITH vals AS (SELECT timestamp '2015-10-01 00:00' AS ts_low -- incl. lower bound
, timestamp '2015-10-31 00:00' AS ts_hi -- excl. upper bound
, text 'google:105697533513134511631' AS uid)
SELECT s.name, sub.*
FROM (
SELECT skill_id AS id, min(score) AS score, 'T' AS source
FROM "TrainerScores", vals v
WHERE fellow_uid = v.uid
AND created_at >= v.ts_low
AND created_at < v.ts_hi
GROUP BY 1
UNION ALL
SELECT skill_id, min(score), 'P'
FROM "PeerScores", vals v
WHERE evaluatee_uid = v.uid
AND created_at >= v.ts_low
AND created_at < v.ts_hi
GROUP BY 1
UNION ALL
SELECT skill_id, min(score), 'S'
FROM "SelfScores", vals v
WHERE fellow_uid = v.uid
AND created_at >= v.ts_low
AND created_at < v.ts_hi
GROUP BY 1
) sub
JOIN "Skills" s USING (id);
要点
首先,我trim从你的语法(可能由你的 ORM 产生)中消除噪音,使其易于阅读:删除多余的双引号,添加 table 别名,trim 杂词...
您对
LEFT [OUTER] JOIN
的使用被破坏了,因为您过滤了左侧 table 的列,这抵消了LEFT JOIN
。替换为[INNER] JOIN
.在
WHERE
子句中使用 sargable 表达式,否则您的查询不能使用普通索引,并且对于大 tables 会非常慢。相关:- Get difference of another field between first and last timestamps of grouping
在 CTE(
WITH
子句)中 一次 提供您的参数 - 这是不需要的在准备好的语句中,您将uid
、ts_low
和ts_hi
作为参数传递。我从您的第一个查询的输出中删除了
"TrainerScores"."fellow_uid"
以简化查询。无论如何,这只是您的输入参数。您可以在加入[=21=之前聚合您各自的主要table ] 一次.
我添加了一列
source
来表示每一行的来源。
旁白:您似乎想匹配整个 2015 年 10 月,但随后排除了 10 月 31 日。这是故意的吗?