热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

编写复杂查询的更好/正确方法-Better/Rightwaytowriteacomplexquery

Thisismytable.这是我的桌子。SELECT*FROM[Message]NowwhatIwantis,Iwantthelistofonlyl


This is my table.

这是我的桌子。

SELECT * FROM [Message]

Message Table Data

Now what I want is, I want the list of only last message which User with Id: 101 has sent or received from any other user. The query which I wrote for it is below

现在我想要的是,我想要的是Id: 101的用户从其他用户发送或接收的唯一的最后一条消息的列表。我为它编写的查询如下

SELECT
(SELECT TOP 1 [Message_id]
 FROM [Message]
 WHERE
 ([Sender_id] = REC.[Sender_id] AND [Receiver_id] = REC.[Receiver_id])
 OR
 ([Sender_id] = REC.[Receiver_id] AND [Receiver_id] = REC.[Sender_id])
 ORDER BY 1 DESC) AS [Message Id],
REC.[Sender_id] AS [Sender Id],
REC.[Receiver_id] AS [Receiver Id],
(SELECT TOP 1 [Message]
 FROM [Message]
 WHERE
 ([Sender_id] = REC.[Sender_id] AND [Receiver_id] = REC.[Receiver_id])
 OR
 ([Sender_id] = REC.[Receiver_id] AND [Receiver_id] = REC.[Sender_id])
 ORDER BY 1 DESC) AS [Message]
FROM
(SELECT DISTINCT [Sender_id], [Receiver_id]
 FROM [Message]
 WHERE [Sender_id] = '101') REC

And I am getting the following result which seems fine.

我得到的结果看起来很好。

Query Results

I'm new to DB queries and it seems that my query is very inefficient and long. Can anyone please suggest a better way to write this query? Also, using JOINS if that might be a better possible way to write this query.

我是DB查询的新手,看起来我的查询效率很低而且很长。谁能提出更好的方式来写这个查询吗?另外,如果使用join可能是编写这个查询的更好的方法。

Note: Please consider Message_id to be just a unique number and not a ordered identity column which in actual scenario may be any generated unique alphanumeric code.

注意:请考虑Message_id只是一个唯一的数字,而不是一个有序的标识列,在实际场景中,它可能是任何生成的唯一字母数字代码。

Thanks.

谢谢。

3 个解决方案

#1


4  

This should do the trick.

这应该能达到目的。

WITH Priorities AS (
   SELECT
      Priority = Row_Number() OVER (PARTITION BY X.Party2 ORDER BY Message_id DESC),
      M.*
   FROM
      dbo.Message M
      OUTER APPLY (VALUES
         (M.Sender_id, M.Receiver_Id),
         (M.Receiver_id, M.Sender_Id)
      ) X (Party1, Party2)
   WHERE
      Party1 = '101'
)
SELECT *
FROM Priorities
WHERE Priority = 1     
;
See this working in a Sql Fiddle

Explanation:

解释:

The real problem is that you don't care whether the selected person is the sender or the receiver. This leads to complication dealing with pulling the value from one column or the other, such as can be solved in typical fashion with a CASE statement.

真正的问题是,您不关心所选的人是发送方还是接收方。这导致从一列或另一列提取值的复杂性,例如可以用CASE语句以典型的方式解决。

However, I'm always a fan of solving things like this relationally instead of procedurally, so I simplified the problem by (basically) doubling up the data. For each source row in the table, we're generating two rows, one where the sender comes first, and one where the receiver comes first. We don't care which one is the sender or receiver, and we can just say that we're looking for Party1 to be id 101, and then want to find, for each Party2 that he exchanged a message with (and whether he was sender or receiver is irrelevant), the most recent one.

然而,我总是喜欢用关系式而不是程序化的方式来解决这些问题,所以我通过(基本上)将数据加倍来简化问题。对于表中的每个源行,我们生成了两行,其中一个是发送者最先到达的,另一个是接收者最先到达的。我们不关心哪一个是发送方或接收方,我们可以说,我们正在寻找Party1 id 101,然后想找,他交换消息的每个Party2(以及他是否发送方或接收方无关),最近的一个。

OUTER APPLY is just a trick for us to avoid doing more CTEs or nested queries (another way to write it). It's like a LEFT JOIN, but lets one use outer references (it refers to columns in table M).

对于我们来说,OUTER APPLY只是一个避免执行更多cte或嵌套查询(另一种编写的方式)的技巧。它类似于左连接,但允许使用外部引用(它引用表M中的列)。

For what it's worth, Message_id doesn't seem like a reliable way to choose the latest message. You should have a date column and order by that instead! (Just add a datetime or datetime2 column to your table, and change the ORDER BY to use it. You never know if messages could be inserted to the table out of order from when they actually occurred--them being out of order should in fact be expected. What if you have to back-insert lost messages? Identity columns are not a good way to guarantee insertion order, in my experience.

无论如何,Message_id似乎不是选择最新消息的可靠方法。您应该有一个日期列,并订购,以代替!(只需向表添加一个datetime或datetime2列,并通过使用它更改顺序。您永远不知道消息是否可以从实际发生时开始按顺序插入到表中——实际上应该预期它们是无序的。如果您必须返回插入丢失的消息怎么办?根据我的经验,身份列不是保证插入顺序的好方法。

P.S. My original take was that you wanted the most recent message sent and the most recent message received, for each sender and receiver. However, that's not what you asked for. I thought I'd leave this in for posterity since it could also be a useful answer to someone:

附注:我最初的想法是,您希望为每个发送者和接收者发送最新的消息和接收最新的消息。然而,那不是你要的。我想我应该把这个留给后人,因为它也可能是对某人有用的回答:

WITH Priorities AS (
   SELECT
      SNum = Row_Number() OVER (PARTITION BY Sender_id ORDER BY Message_id DESC),
      PNum = Row_Number() OVER (PARTITION BY Receiver_id ORDER BY Message_id DESC),
      *
   FROM
      Message
   WHERE
      '101' IN (Sender_id, Receiver_id)
)
SELECT *
FROM Priorities
WHERE 1 IN (SNum, PNum)
;

#2


3  

If you want the most recent message to/from another user, calculate the recency (based on message_id) for the other user as both sender and receiver. The trick is to partition using the other user as the partitioning key.

如果您希望另一个用户的最新消息,则计算另一个用户作为发送方和接收方的近似值(基于message_id)。诀窍是使用其他用户作为分区键进行分区。

Then choose the first one in the outer query:

然后选择外部查询中的第一个:

select m.*
from (select m.*,
             row_number() over (partition by (case when sender_id = 101 then receiver_id else sender_id end)
                                order by message_id desc) as seqnum
      from message m
      where 101 in (sender_id, receiver_id)
     ) m
where seqnum = 1;

#3


0  

Hope this helps

希望这有助于

SELECT * FROM (
SELECT Message_id, Sender_id, Receiver_id, Message, RANK() OVER(PARTITION BY Sender_id, Receiver_id ORDER BY Message_id DESC) OBD FROM Message
WHERE Sender_id = 101 OR Receiver_id = 101) A WHERE A.OBD = 1

推荐阅读
  • 本文介绍了游标的使用方法,并以一个水果供应商数据库为例进行了说明。首先创建了一个名为fruits的表,包含了水果的id、供应商id、名称和价格等字段。然后使用游标查询了水果的名称和价格,并将结果输出。最后对游标进行了关闭操作。通过本文可以了解到游标在数据库操作中的应用。 ... [详细]
  • ALTERTABLE通过更改、添加、除去列和约束,或者通过启用或禁用约束和触发器来更改表的定义。语法ALTERTABLEtable{[ALTERCOLUMNcolu ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • MySQL多表数据库操作方法及子查询详解
    本文详细介绍了MySQL数据库的多表操作方法,包括增删改和单表查询,同时还解释了子查询的概念和用法。文章通过示例和步骤说明了如何进行数据的插入、删除和更新操作,以及如何执行单表查询和使用聚合函数进行统计。对于需要对MySQL数据库进行操作的读者来说,本文是一个非常实用的参考资料。 ... [详细]
  • WhenImtryingtorunthefollowing:当我试图运行以下内容时:ContentValuescvnewContentValues();cv ... [详细]
  • 在Android Studio中查看SQLite数据库
    原来查看数据库内容,我们一般都是将数据库文件从手机导出,再用专门的软件打开查看,比较繁琐。最近发现了一个比较方便的方法:使用工具stetho。使用方式在gradle中配置depen ... [详细]
  • 有没有人用过sqlite?关于tablehasnocolumnnamedcolumn插入数据的时候报上边的错。问题是我明明有这一列。直接在sqlitedevoloper里执 ... [详细]
  • Easyui + asp.net mvc + sqlite 开发教程(录屏)适合入门
    第一节:前言(技术简介)EasyUI是一套js的前端框架利用它可以快速的开发出好看的前端系统web它是在jquery的框架基础上面现在越来越多的企业用它来开发web系统 ... [详细]
  • 推荐系统遇上深度学习(十七)详解推荐系统中的常用评测指标
    原创:石晓文小小挖掘机2018-06-18笔者是一个痴迷于挖掘数据中的价值的学习人,希望在平日的工作学习中,挖掘数据的价值, ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • SQLite–CONSTRAINTS(约束)约束是数据列在表上执行的规则。这些是用来限制的数据类型可以进入一个表。这样可以确保数据的准确性和可靠性在数据库中。    级或表级约束可 ... [详细]
  • SQLite3是一个广泛使用的数据库,从linux,windows到安卓都有SQLite的应用。本文介绍SQLite3在windows上的编译。SQLite3提供了多种源代码的下载 ... [详细]
  • 州的先生(https:zmister.com)在很多项目中都有使用到SQLite数据库作为数据存储的工具,其中包括一些桌面图形界面程序和线上的Web应用程序。至今为止,它们都运行良 ... [详细]
  • Python使用SQLite1.sqlite3的安装python2.5.x以上版本默认自带sqlite3模块。2.链接sqlite3数据库```#导入sqlite3模块import ... [详细]
  • 背景使用sqlite3的命令实现数据去重,与无效数据删除等操作。所有操作均封装在shellscript中。创建数据库邮件数据库:UserEmail.dbEmail表:TABLE_EM ... [详细]
author-avatar
小歆歆
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有