我有一个与MySQL有关的问题。这是我的表格:
keyword args title namespace_id ratio
en 1 A 23 0.5
en 1 B 89 0.6
en 0 C 89 0.4
foo 1 Foo 23 0.7
bar 1 Bar 89 0.3
我想要一个没有(keywords,args)重复的所有行的列表。如果存在重复项,则应按我提供的namespace_ids顺序选择所选行。左边的行应按比例排序。
使用namespace_id命令23,89,x,y:
的示例结果keyword args title namespace_id ratio
foo 1 Foo 23 0.7
en 1 A 23 0.5
en 0 C 89 0.4
bar 1 Bar 89 0.3
命名空间顺序为89,23,x,y的示例结果:
keyword args title namespace_id ratio
foo 1 Foo 23 0.7
en 1 B 89 0.6
en 0 C 89 0.4
bar 1 Bar 89 0.3
我有没有办法直接在MySQL中使用它?我查看了GROUP BY,ORDER BY并注意到了GROUP_CONCAT()函数,但我没有设法正确地将它们放在一起。我想要的声明是:
SELECT keyword, args, title, namespace_id, ratio
FROM tbl
GROUP BY keyword, args
ORDER BY ratio DESC;
但现在我不知道如何引入namespace_id命令。
我发现了类似的问题: MySQL: "order by" inside of "group by" 答案那里接近我想要的,但是,我的namespace_id顺序是变化的,不能通过MAX()函数计算。
编辑:这里的挑战是告诉GROUP BY
选择哪一行。正常的ORDER BY
显然没有,它只使用GROUP BY
的输出。
答案 0 :(得分:1)
尝试使用FIELD()和子查询:
SELECT t1.keyword, t1.args, t1.title, t1.namespace_id, t1.ratio
FROM tbl t1, (SELECT keyword, args, MIN(FIELD(namespace_id, 23, 89))
minfield FROM tbl GROUP BY keyword, args) t2
WHERE t1.keyword = t2.keyword AND t1.args = t2.args AND
FIELD(t1.namespace_id, 23, 89) = t2.minfield
ORDER BY ratio DESC;
或自我加入:
SELECT t1.keyword, t1.args, t1.title, t1.namespace_id, t1.ratio
FROM tbl t1
LEFT OUTER JOIN tbl t2 ON
t1.keyword = t2.keyword AND
t1.args = t2.args AND
FIELD(t1.namespace_id, 23, 89) < FIELD(t2.namespace_id, 23, 89)
WHERE t2.keyword IS NULL AND t2.args IS NULL
ORDER BY t1.ratio DESC;
编辑:看一些支持OLAP操作的(商业)DBMS也是值得的(如果你能够选择,如果你正在处理大量数据)。对于Georg的案例,我认为OVER和PARTITION BY关键字会有所帮助:http://publib.boulder.ibm.com/infocenter/rbhelp/v6r3/topic/com.ibm.redbrick.doc6.3/sqlrg/sqlrg36.htm#sii06377181
答案 1 :(得分:0)
我认为这就是你想要的 -
SELECT t1.* FROM tbl t1
JOIN(SELECT keyword, args, MIN(ratio) ratio FROM tbl GROUP BY keyword, args) t2
ON t1.keyword = t2.keyword AND t1.args = t2.args AND t1.ratio = t2.ratio
ORDER BY ratio DESC;
和第二个 -
SELECT t1.* FROM tbl t1
JOIN(SELECT keyword, args, MAX(ratio) ratio FROM tbl GROUP BY keyword, args) t2
ON t1.keyword = t2.keyword AND t1.args = t2.args AND t1.ratio = t2.ratio
ORDER BY ratio DESC;
答案 2 :(得分:0)
您可以使用FIELD()生成如下自定义排序顺序:
SELECT keyword, args, title, namespace_id, FIELD(namespace_id, 32, 89) sorting, ratio
FROM tbl
GROUP BY keyword, args
ORDER BY sorting DESC, ratio DESC;
请注意,FIELD()
函数中未指定的任何namespace_id都将收到0 sorting
值,因此要在结果中显示 first 这些项目,您必须指定它们的顺序相反,并使用DESC
作为排序顺序。
因此FIELD(namespace_id, 32, 89)
ORDER BY sorting DESC
会导致:
x x 89 x
x x 32 x
...
FIELD(namespace_id, 89, 32)
与ORDER BY sorting DESC
的结果将导致:
x x 32 x
x x 89 x
...
答案 3 :(得分:0)
执行此操作的一种略微讨厌的方法是按照许多布尔表达式排序,如下所示:
SELECT keyword, args, title, namespace_id, ratio
FROM tbl
GROUP BY keyword, args
ORDER BY namespace_id != 89,
namespace_id != 23,
namespace_id != x,
namespace_id != y,
ratio DESC;
显然,这很快变得不切实际。
如果您真的必须在SQL端执行此操作,我建议您创建另一个包含列namespace_id
(应该具有UNIQUE约束)和priority
(或类似)的表。然后,您在该表中JOIN
和ORDER BY priority
。
您可能已经拥有namespace_id
引用的命名空间的表。在这种情况下,只需在该表中添加priority
列。
答案 4 :(得分:0)
重新考虑您的问题以及您对我之前回答的评论后,我认为您无法做到这一点。原因如下:
由于您希望在排序之后过滤行,因此您唯一的选择是HAVING
子句,据我所知,这是ORDER BY
之后处理的唯一事物。条款。
由于HAVING
子句仅单独查看每一行,但您希望按其在集合中的相对位置进行过滤(即您只希望每个子集的第一行具有相同的关键字/ arg),必须将其作为一个值“走私”到每一行。我简单地想过这个选项,但只能提出废话。
跳过GROUP
,获取ORDER
权限(通过将可排序的priority
值与每个namespace_id
相关联),然后在您的代码中,使用键入keyword
和arg
的数据结构,并在使用结果集填充时忽略重复项。
如果出于某种神秘的原因绝对必须在SQL中执行所有操作,您可以通过创建在两列上具有UNIQUE
约束的临时表(在内存中)来模拟我上面描述的内容并执行{{ 1}}
作为旁注:每当您注意到您希望SQL对依赖于结果集中其他行的行执行某些操作时,您可能会运气不好。我反复讨论过我认为很容易的案例,直到我发现我接近结果集,好像它们是循环。我最喜欢的轶事是我拼命地从前一行中的对应物中减去一列中的值的时间。有时候你可以试着用怪异的INSERT IGNORE INTO temp_table SELECT ...
来破解你的出路(将相关的行拉到一起),但即使这样可行,也可能很贵。