MySQL 将行透视为相似记录的列

发布于 2024-10-01 05:55:05 字数 1557 浏览 2 评论 0原文

我有两个表:

  1. tbl_sms
  2. tbl_bids

上面两个表包含类似这样的内容:

tbl_sms:

Post_ID | User_ID | SMS_Sent_DT
---------------------------------
123     |   007   |   2010-05-14 10:15:25
123     |   008   |   2010-05-14 10:18:32
123     |   009   |   2010-05-14 10:23:05
123     |   010   |   2010-05-14 10:23:06

tbl_bids:

Post_ID | User_ID | Bid_DT
--------------------------
123     |   010   |   2010-05-14 10:27:25
123     |   008   |   2010-05-14 10:28:32
123     |   009   |  2010-05-14 10:28:47
123     |   007   |   2010-05-14 10:35:06

通过这两个表,我试图实现以下目标:

Post_ID | First_BID_Time | First_BID_SMS_TIME | Second_BID_Time | Second_BID_SMS_Time | Third_BID_Time | Third_BID_SMS_Time
-----------------------------------------------------------------------------------------------------------------------------------
123     | 2010-05-14 10:27:25 | 2010-05-14 10:23:06 | 2010-05-14 10:28:32 | 2010-05-14 10:18:32 | 2010-05-14 10:28:47 | 2010-05-14 10:23:05

我编写的查询是:

   SELECT b.post_id,
          sms.message_sent_at as notif_sent1,
          b.message_sent_at as notif_accepted1,
          DATEDIFF(b.message_sent_at, sms.message_sent_at) AS delay1
     FROM tbl_bids b
LEFT JOIN tbl_sms_status sms ON (sms.jobid = b.post_id AND b.user_id = sms.userid)
    WHERE b.post_id = sms.jobid
 ORDER BY b.post_id ASC

这给了我正确的结果,但它们是没有按照我想要的方式旋转。

请有人帮我解决这个问题。我欢迎任何解决方案,无论是完整的冗长查询还是过程。

I have got two tables:

  1. tbl_sms
  2. tbl_bids

The above two table holds something like this:

tbl_sms:

Post_ID | User_ID | SMS_Sent_DT
---------------------------------
123     |   007   |   2010-05-14 10:15:25
123     |   008   |   2010-05-14 10:18:32
123     |   009   |   2010-05-14 10:23:05
123     |   010   |   2010-05-14 10:23:06

tbl_bids:

Post_ID | User_ID | Bid_DT
--------------------------
123     |   010   |   2010-05-14 10:27:25
123     |   008   |   2010-05-14 10:28:32
123     |   009   |  2010-05-14 10:28:47
123     |   007   |   2010-05-14 10:35:06

With those two tables I'm trying to achieve the following:

Post_ID | First_BID_Time | First_BID_SMS_TIME | Second_BID_Time | Second_BID_SMS_Time | Third_BID_Time | Third_BID_SMS_Time
-----------------------------------------------------------------------------------------------------------------------------------
123     | 2010-05-14 10:27:25 | 2010-05-14 10:23:06 | 2010-05-14 10:28:32 | 2010-05-14 10:18:32 | 2010-05-14 10:28:47 | 2010-05-14 10:23:05

The query I had written is:

   SELECT b.post_id,
          sms.message_sent_at as notif_sent1,
          b.message_sent_at as notif_accepted1,
          DATEDIFF(b.message_sent_at, sms.message_sent_at) AS delay1
     FROM tbl_bids b
LEFT JOIN tbl_sms_status sms ON (sms.jobid = b.post_id AND b.user_id = sms.userid)
    WHERE b.post_id = sms.jobid
 ORDER BY b.post_id ASC

That gives me the correct result but they are not pivoted the way I want it to be.

Can please someone help me out with this one. I welcome any solution be it a full lengthy query or a procedure.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

蓝天白云 2024-10-08 05:55:05

在 SQL Server 中,使用 ROW_NUMBER() 函数或 CROSS APPLY 构造可以轻松实现这一点。在 MySQL 中,这更难

一种解决方案是在 MySQL 中模拟 ROW_NUMBER()使用变量。这样就可以返回按出价时间排名的每个帖子 ID 的出价,并获取 user_ids。从那时起,将 SMS 时间左连接到 post_id/user_id 组合就很容易了。按照链接中的示例,代码将类似于:

SELECT tmp.Post_ID, tmp.ranking, tmp.user_ID, tmp.Bid_DT, s.SMS_DT
FROM ( 
  SELECT 
    b.Post_ID, b.user_ID, b.Bid_DT, 
    IF( @prev <> ID, @rownum := 1, @rownum := @rownum+1 ) AS ranking, 
    @prev := ID 
  FROM tbl_bids b 
  JOIN (SELECT @rownum := NULL, @prev := 0) AS r 
  ORDER BY b.Post_ID, b.BID_DT 
) AS tmp
LEFT JOIN tbl_sms s
  ON tmp.Post_ID = s.Post_ID AND tmp.user_ID = s.user_ID 
WHERE tmp.rank <= 3 -- Top 3, adjust when more are necessary 
ORDER BY post_ID, ranking; 

然后您将得到如下输出:

Post_ID | Ranking  | User_ID | Bid_DT                 | SMS_DT
---------------------------------------------------------------------------
123     |    1     |   010   |   2010-05-14 10:27:25  | 2010-05-14 10:23:06
123     |    2     |   008   |   2010-05-14 10:28:32  | ....
123     |    3     |   009   |   2010-05-14 10:28:47  | ....
123     |    4     |   007   |   2010-05-14 10:35:06  | ....
124     |    1     | .......

您可以将此结果存储在临时表中:

CREATE TEMPORARY TABLE RankedBids(Post_ID INTEGER, Ranking INTEGER, User_ID INTEGER, Bid_DT DATETIME, SMS_DT DATETIME)
INSERT INTO Rankedbids SELECT.... (use above query)

不幸的是,由于 MySQL 限制 您不能在查询中使用对同一个临时表的多个引用,因此您必须拆分该表按排名:

CREATE TEMPORARY TABLE RankedBids1(Post_ID INTEGER, User_ID INTEGER, Bid_DT DATETIME, SMS_DT DATETIME)
CREATE TEMPORARY TABLE RankedBids2....
INSERT INTO Rankedbids1 SELECT Post_ID, User_ID, Bid_DT, SMS_DT FROM RankedBids WHERE Ranking = 1
INSERT INTO RankedBids2...

如果记录集非常大,则可以在 Post_ID 上分配(主键)索引以加速旋转查询。

现在您可以旋转这些数据:

SELECT R1.Post_ID, R1.Bid_DT AS Bid_DT1, R1.SMS_DT AS SMS_DT1 .... 
FROM RankedBids1 R1
LEFT JOIN RankedBids2 R2 ON R1.Post_ID = R2.Post_ID
LEFT JOIN RankedBids3 R3 ON ........

OMG Ponies 有一个观点,围绕未旋转的表构建系统更具可扩展性。所以,如果你不需要转向,就不要转向。

In SQL Server this would be easy to accomplish using a ROW_NUMBER() function or CROSS APPLY construct. In MySQL this is harder.

One solution is to emulate ROW_NUMBER() in MySQL using variables. This way it is possible to return the bids for each post id ranked on bid time, and get the user_ids. From there on it is an easy matter to LEFT JOIN the SMS time to the post_id/user_id combination. Following the example in the link, the code will be something like:

SELECT tmp.Post_ID, tmp.ranking, tmp.user_ID, tmp.Bid_DT, s.SMS_DT
FROM ( 
  SELECT 
    b.Post_ID, b.user_ID, b.Bid_DT, 
    IF( @prev <> ID, @rownum := 1, @rownum := @rownum+1 ) AS ranking, 
    @prev := ID 
  FROM tbl_bids b 
  JOIN (SELECT @rownum := NULL, @prev := 0) AS r 
  ORDER BY b.Post_ID, b.BID_DT 
) AS tmp
LEFT JOIN tbl_sms s
  ON tmp.Post_ID = s.Post_ID AND tmp.user_ID = s.user_ID 
WHERE tmp.rank <= 3 -- Top 3, adjust when more are necessary 
ORDER BY post_ID, ranking; 

You'll then have an output like this:

Post_ID | Ranking  | User_ID | Bid_DT                 | SMS_DT
---------------------------------------------------------------------------
123     |    1     |   010   |   2010-05-14 10:27:25  | 2010-05-14 10:23:06
123     |    2     |   008   |   2010-05-14 10:28:32  | ....
123     |    3     |   009   |   2010-05-14 10:28:47  | ....
123     |    4     |   007   |   2010-05-14 10:35:06  | ....
124     |    1     | .......

You can store this result in a temporary table:

CREATE TEMPORARY TABLE RankedBids(Post_ID INTEGER, Ranking INTEGER, User_ID INTEGER, Bid_DT DATETIME, SMS_DT DATETIME)
INSERT INTO Rankedbids SELECT.... (use above query)

Unfortunately due to a MySQL limitation you can't use multiple references to the same temporary table in a query, so you'll have to split out this table by ranking:

CREATE TEMPORARY TABLE RankedBids1(Post_ID INTEGER, User_ID INTEGER, Bid_DT DATETIME, SMS_DT DATETIME)
CREATE TEMPORARY TABLE RankedBids2....
INSERT INTO Rankedbids1 SELECT Post_ID, User_ID, Bid_DT, SMS_DT FROM RankedBids WHERE Ranking = 1
INSERT INTO RankedBids2...

If the recordset is very large, it pays off to assign a (primary key) index on Post_ID to speed up the pivoting query.

Now you can pivot this data:

SELECT R1.Post_ID, R1.Bid_DT AS Bid_DT1, R1.SMS_DT AS SMS_DT1 .... 
FROM RankedBids1 R1
LEFT JOIN RankedBids2 R2 ON R1.Post_ID = R2.Post_ID
LEFT JOIN RankedBids3 R3 ON ........

OMG Ponies has a point though, it's more scalable to build your system around an unpivoted table. So if you don't need to pivot, don't.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文