如何编写oracle SQL查询以特定顺序获取匹配和不匹配的行对(基于键列)

Posted

技术标签:

【中文标题】如何编写oracle SQL查询以特定顺序获取匹配和不匹配的行对(基于键列)【英文标题】:How to write oracle SQL query to get matching and non-matching pair of rows (on the basis of key columns) in a certain order 【发布时间】:2020-07-06 10:53:40 【问题描述】:

我有以下示例数据:

ID  BOOK_NAME  AUTHOR  YEAR  PAGE_COUNT  PRICE  BUCKET
1   Book1      A1      2001  450         44     1
2   Book2      A2      2002  550         50     1
3   Book1      A1      2001  450         44     2
4   Book3      A3      2003  350         38     1
5   Book2      A2      2002  550         50     2
6   Book3      A3      2003  350         38     2
7   Book4      A4      2006  400         60     1
8   Book4      A4      2006  410         60     2
9   Book5      A5      1999  600         58     1
10  Book6      A6      2004  650         76     2

上面的示例数据包含来自两个存储桶 - 1 和 2 的书籍。要求以显示两个存储桶之间匹配和不匹配书籍的方式对书籍进行排序,即一本书被称为 MATCHED 如果它存在于两个存储桶中(通过匹配关键列 - BOOK_NAME、AUTHOR、YEAR、PAGE_COUNT、PRICE),否则为 UNMATCHED。即使单个列在任何一对的两个存储桶之间都不匹配,这本书也被视为 UNMATCHED。以下是上述输入的预期输出。

STATUS     ID  BOOK_NAME  AUTHOR  YEAR  PAGE_COUNT  PRICE  BUCKET
MATCHED    2   Book2      A2      2002  550         50     1
MATCHED    5   Book2      A2      2002  550         50     2
MATCHED    1   Book1      A1      2001  450         44     1
MATCHED    3   Book1      A1      2001  450         44     2
MATCHED    4   Book3      A3      2003  350         38     1
MATCHED    6   Book3      A3      2003  350         38     2
UNMATCHED  7   Book4      A4      2006  400         60     1
UNMATCHED  9   Book5      A5      1999  600         58     1
UNMATCHED  10  Book6      A6      2004  650         76     2
UNMATCHED  8   Book4      A4      2006  410         60     2

另外-

    匹配的货币对应按 PRICE 列排序,即价格最高的货币对应排在第一位。 在列表的不匹配部分中,项目应按存储桶排序,即所有存储桶 1 不匹配的项目应放在一起,然后所有存储桶 2 不匹配的项目应出现。 对于未匹配部分中的每个存储桶,然后应按 PRICE 列对项目进行进一步排序,即价格最高的一对应排在第一位。

所以,问题在于按节规则对数据集进行排序。请提供单个查询解决方案的帮助,我知道可以通过获取数据并以任何编码语言(如 Java)应用逻辑来轻松完成。但基于设计要求,我对基于 SQL 的简单解决方案感兴趣。请帮忙。

【问题讨论】:

【参考方案1】:

您可以使用窗口函数。假设这些书在桶中没有重复:

select (case when count(*) over (partition by BOOK_NAME, AUTHOR, YEAR, PAGE_COUNT, PRICE) = 2
             then 'Matched' else 'Unmatched'
        end) as status,
       t.*
from t
order by status,
         (case when count(*) over (partition by BOOK_NAME, AUTHOR, YEAR, PAGE_COUNT, PRICE) = 2 then price end) desc,
         bucket

【讨论】:

【参考方案2】:

感谢戈登的回复!它给了我解决问题的方向。我在下面做了一些调整以满足我的需要。

select (case when count(*) over (partition by BOOK_NAME, AUTHOR, YEAR, PAGE_COUNT, PRICE) = 2
             then 'Matched' else 'Unmatched'
        end) as status,
       t.*
from t
order by status,
         (case when status = 'Matched' then price end) desc,
         (case when status = 'Unmatched' then bucket end),
         (case when status = 'Matched' then BOOK_NAME end),
         (case when status = 'Matched' then AUTHOR end),
         (case when status = 'Matched' then YEAR end),
         (case when status = 'Matched' then PAGE_COUNT end),
         (case when status = 'Matched' then bucket end),
         (case when status = 'Unmatched' then price end) desc

【讨论】:

以上是关于如何编写oracle SQL查询以特定顺序获取匹配和不匹配的行对(基于键列)的主要内容,如果未能解决你的问题,请参考以下文章

如何选择包含特定子字符串的单词列表作为 SQL 查询(oracle)的一部分?

如何强制 SQL Server 以特定顺序执行查询

如何编写涉及多个选择的 Oracle SQL 查询

oracle sql查询以获取没有空格的列值

oracle中如何获取最后执行的SQL语句并绑定变量值

如何在 Oracle SQL 中查找最具体的匹配行