我有下面的表格,我试着找到如何
获得结果是文章ID数组或文章行,
同时匹配标签' hiphop'' rock'' single'在ArticleTag0
和ArticleTag1
表中。
现在我使用下面的代码,
将每个文章ID数组标记为不同的标记类型,
例如,如果文章x Tag0中标记的文章ID行为[0,2,4,6]且文章x Tag1为[0,4,9],则 然后比较每个数组得到的数字都在上面两个数组get,[0,4]。
我想知道有没有更好的查询一次选择它们?考虑绩效
表
CREATE TABLE IF NOT EXISTS "Article"(
"ArticleId" SERIAL NOT NULL,
"PublishDate" timestamp without time zone,
"Active" bit NOT NULL,
PRIMARY KEY ("ArticleId")
);
CREATE TABLE IF NOT EXISTS "Tag0"(
"TagId" SERIAL NOT NULL,
"Name" varchar,
"Active" bit NOT NULL,
PRIMARY KEY ("TagId")
);
CREATE TABLE IF NOT EXISTS "Tag1"(
"TagId" SERIAL NOT NULL,
"Name" varchar,
"Active" bit NOT NULL,
PRIMARY KEY ("TagId")
);
CREATE TABLE IF NOT EXISTS "ArticleTag0"(
"ArticleTagId" SERIAL NOT NULL,
"ArticleId" integer NOT NULL,
"TagId" integer NOT NULL,
FOREIGN KEY ("ArticleId") REFERENCES "Article" ("ArticleId") ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY ("TagId") REFERENCES "Tag0" ("TagId") ON DELETE CASCADE ON UPDATE CASCADE,
PRIMARY KEY ("ArticleTagId")
);
CREATE TABLE IF NOT EXISTS "ArticleTag1"(
"ArticleTagId" SERIAL NOT NULL,
"ArticleId" integer NOT NULL,
"TagId" integer NOT NULL,
FOREIGN KEY ("ArticleId") REFERENCES "Article" ("ArticleId") ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY ("TagId") REFERENCES "Tag1" ("TagId") ON DELETE CASCADE ON UPDATE CASCADE,
PRIMARY KEY ("ArticleTagId")
);
码
用户输入参数
inputGenres(Tag0) - [' hiphop',' rock' ]
inputReleaseType(Tag1) - [' single' ]
...
// inputGenres
var inputGenresArticleIdList = [];
if (inputGenres[0] == 'all') {
var query = 'SELECT * FROM "Article"';
var params = [];
var selectArticle = yield crudDatabase(db,query,params);
if (typeof selectArticle.error !== 'undefined') {
response.meta.code = '500';
} else {
for (var i = 0; i < selectArticle.result.rows.length; i++) {
inputGenresArticleIdList.push(selectArticle.result.rows[i].ArticleId);
}
}
} else {
var query = 'SELECT DISTINCT ON ("ArticleId") * FROM "ArticleTag0" LEFT OUTER JOIN "Tag0" ON ("ArticleTag0"."TagId" = "Tag0"."TagId") WHERE "Name" IN (';
for (var i = 0; i < inputGenres.length; i++) {
if (i > 0) {
query += ',';
}
query += '$' + (i + 1);
}
query += ')';
var params = inputGenres;
var selectArticleTag0 = yield crudDatabase(db,query,params);
if (typeof selectArticleTag0.error !== 'undefined') {
response.meta.code = '500';
} else {
for (var i = 0; i < selectArticleTag0.result.rows.length; i++) {
inputGenresArticleIdList.push(selectArticleTag0.result.rows[i].ArticleId);
}
}
}
console.log(inputGenresArticleIdList);
// end: inputGenres
// inputReleaseType
var inputReleaseTypeArticleIdList = [];
if (inputReleaseType[0] == 'all') {
var query = 'SELECT * FROM "Article"';
var params = [];
var selectArticle = yield crudDatabase(db,query,params);
if (typeof selectArticle.error !== 'undefined') {
response.meta.code = '500';
} else {
for (var i = 0; i < selectArticle.result.rows.length; i++) {
inputReleaseTypeArticleIdList.push(selectArticle.result.rows[i].ArticleId);
}
}
} else {
var query = 'SELECT DISTINCT ON ("ArticleId") * FROM "ArticleTag4" LEFT OUTER JOIN "Tag4" ON ("ArticleTag4"."TagId" = "Tag4"."TagId") WHERE "Name" IN (';
for (var i = 0; i < inputReleaseType.length; i++) {
if (i > 0) {
query += ',';
}
query += '$' + (i + 1);
}
query += ')';
var params = inputReleaseType;
var selectArticleTag4 = yield crudDatabase(db,query,params);
if (typeof selectArticleTag4.error !== 'undefined') {
response.meta.code = '500';
} else {
for (var i = 0; i < selectArticleTag4.result.rows.length; i++) {
inputReleaseTypeArticleIdList.push(selectArticleTag4.result.rows[i].ArticleId);
}
}
}
console.log(inputReleaseTypeArticleIdList);
// end: inputReleaseType
... then loop each array and compare
答案 0 :(得分:1)
通常,使用一个SQL语句完成工作会更好:它不那么复杂,它可以节省往返服务器的往返,它可以利用数据库的算法和优化。
您可以使用以下语句获得所需的结果:
select *
from "Article" a
where exists (
select 1
from "ArticleTag0" at0,
"Tag0" t0
where at0."ArticleId" = a."ArticleId"
and t0."TagId" = at0."TagId"
and t0."Name" in ('hiphop','rock')
)
and exists (
select 1
from "ArticleTag1" at1,
"Tag1" t1
where at1."ArticleId" = a."ArticleId"
and t1."TagId" = at1."TagId"
and t1."Name" in ('single')
);
当然,您仍然需要更改文字(例如'hiphop'
)来绑定变量($i
)。 &#39;所有&#39;标签选项可以通过用exists(...)
替换相应的true
块来完成。
但我建议你稍微重新设计你的架构。如何用数组表示文章的标签?
create table article(
articleId serial primary key,
publishDate timestamp without time zone,
active boolean, -- clearer that 'bit'
genres text[], -- array of genre tags
releases text[] -- array of release tags
);
优点:
ArticleTag0
)。让我们插入一些值:
tags=# insert into article(publishDate,active,genres,releases) values ('2015-09-01',true,'{"hiphop"}','{"single"}');
INSERT 0 1
tags=# insert into article(publishDate,active,genres,releases) values ('2015-10-01',true,'{"rock","blues"}','{"album"}');
INSERT 0 1
tags=# insert into article(publishDate,active,genres,releases) values ('2015-11-01',true,'{"pop"}','{"ep"}');
INSERT 0 1
tags=# select * from article;
articleid | publishdate | active | genres | releases
-----------+---------------------+--------+--------------+----------
1 | 2015-09-01 00:00:00 | t | {hiphop} | {single}
2 | 2015-10-01 00:00:00 | t | {rock,blues} | {album}
3 | 2015-11-01 00:00:00 | t | {pop} | {ep}
(3 rows)
现在查询尽可能简单明了(&&
运算符意味着重叠&#39;):
tags=# select * from article where genres && '{"hiphop","rock"}' and releases && '{"single"}';
articleid | publishdate | active | genres | releases
-----------+---------------------+--------+----------+----------
1 | 2015-09-01 00:00:00 | t | {hiphop} | {single}
(1 row)
此外,它还简化了查询文本的构建:使用select * from article where genres && $1 and releases && $2;
并为$1
和$2
生成适当的字符串。
要加快查询速度,您可以创建两个支持&&
数组运算符的GIN索引:
create index on article using gin(genres);
create index on article using gin(releases);