如何根据SQL中的条件选择组中的行?

时间:2018-04-28 10:43:15

标签: mysql sql select group-by

问题 请考虑下表:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:mf="http://example.com/mf"
    exclude-result-prefixes="xs mf"
    version="2.0">

    <xsl:param name="start-id">15492293</xsl:param>

    <xsl:output method="text"/>

    <xsl:key name="parent" match="related-documents/*" use="relation/child-doc/document-id/doc-number"/>

    <xsl:function name="mf:get-ancestor-ids" as="xs:integer*">
        <xsl:param name="item" as="element()"/>
        <xsl:variable name="parent-id"
          select="$item/relation/parent-doc/document-id/doc-number"/>
        <xsl:variable name="parent"
          select="key('parent', $parent-id, root($item))"/>
        <xsl:sequence 
            select="xs:integer($parent-id), $parent/mf:get-ancestor-ids(.)"/>
    </xsl:function>

    <xsl:template match="/">
        <xsl:value-of select="$start-id, mf:get-ancestor-ids(key('parent', $start-id))" separator=" -> "/>
    </xsl:template>

</xsl:stylesheet>

对于每个+--------------+--------+--------+ | transactionID | Sgroup | Rgroup | +--------------+--------+--------+ | 1 | A | I | | 1 | A | J | | 2 | B | B | | 2 | B | K | +--------------+--------+--------+ (2行与ID 1关联,两行ID为ID 2)我想选择transactionID的行,如果Sgroup = Rgroup中的任何行满足条件。否则,我想随机选择一行。对于每个transactionID,最多一行满足transactionID。我怎么能这样做?

尝试解决方案 我知道如何选择满足条件Sgroup = Rgroup的行,如下所示:

Sgroup = Rgroup

我也知道如果不满足条件,如何随机选择一行(感谢this question):

SELECT *
FROM Transaction 
WHERE Sgroup = Rgroup;

+---------------+--------+--------+
| transactionID | Sgroup | Rgroup |
+---------------+--------+--------+
|             2 | B      | B      |
+---------------+--------+--------+

如何将这两个表达式合并为一个?我尝试使用CASE表达式我没有达到目标。有人可以建议一个解决方案吗?

示例代码以下是生成表格的代码:

SELECT * FROM
(SELECT *
FROM Transaction
WHERE NOT transactionID IN
(SELECT transactionID
FROM Transaction 
WHERE Sgroup = Rgroup)
ORDER BY RAND()) AS temp
GROUP BY temp.transactionID;

+---------------+--------+--------+
| transactionID | Sgroup | Rgroup |
+---------------+--------+--------+
|             1 | A      | I      |
+---------------+--------+--------+

1 个答案:

答案 0 :(得分:3)

我认为变量可能是最简单的解决方案,如果你的意思是&#34;随机&#34;:

select t.*
from (select t.*,
             (@rn := if(@i = transactionID, @rn + 1,
                        if(@i := transactionID, 1, 1)
                       )
             ) as rn
      from (select t.*
            from t
            order by transactionID, (sgroup = rgroup) desc, rand()
           ) t cross join
           (select @i := -1, @rn := 0) params
     ) t
where rn = 1;

如果是&#34;随机&#34;你的意思是&#34;任意&#34;,你可以使用这个快速而肮脏的技巧:

(select t.*
 from t
 where sgroup = rgroup
)
union all
(select t.*
 from t
 where not exists (select 1 from t t2 where t2.id = t.id and t2.sgroup = t2.rgroup)
 group by transactionID
);

这会使用可怕的select *group by,这是我强烈反对在几乎所有情况下使用的东西。但是,在这种情况下,您专门尝试将每个组缩减为 indeterminate 行,因此它看起来并不那么糟糕。我会注意到MySQL并不保证结果集中的列都来自同一行,尽管实际上它们也是如此。

最后,如果每行都有唯一的主键,则可以使用最简单的解决方案:

select t.*
from t
where t.id = (select t2.id
              from t t2
              where t2.transactionID = t.transactionID
              order by (rgroup = sgroup) desc, rand()
             );