使用 Union All 按日期顺序回显 SQL 数据

Posted

技术标签:

【中文标题】使用 Union All 按日期顺序回显 SQL 数据【英文标题】:Echo SQL data in order of date added using Union All 【发布时间】:2015-12-18 22:57:34 【问题描述】:

因此,我正在与客户合作实施一个与 StackExchange 上的“徽章和特权系统”类似的系统。尽管在她的系统中,她希望为她的员工使用积分和奖励。这是相同的基本原理。用户因良好的团队合作而获得奖励积分,并从这些积分中获得奖励。我认为添加 SE 用来在顶部导航栏中显示这些的相同类型的功能会很方便,它会按照您获得其中任何一个的日期的顺序显示您的代表和徽章。这是我的问题,我找到了从两个单独的表中一起检索数据的帮助,但不确定如何按获得的日期顺序显示这些结果?举个例子:

User ID #1 has earned 50 points on 18/12/2015 将在 ap_user_points 表中

User ID #1 has earned 'The Gift Voucher' reward on '17/12/2015'

如果我简单地说:

echo $row8['reward'] . $row8['points_added']

它会回显为:

The Gift Voucher 50

我需要它的地方按日期排序:

50

The Gift Voucher

如果您查看导航栏中的代表和徽章图标,您会看到我在这里看到的内容,这是一个类似的系统。

            <?php
$user_id = $_SESSION['userid'];                 
$sql8 = "
SELECT r.reward_id,                    
       r.user_id, 
       r.reward as reward, 
       r.date_earned as date_earned,
       r.badge_desc,

       NULL AS points_added,               
       NULL AS added_for,
       NULL AS date_added
   FROM ap_user_rewards as r 
   WHERE r.user_id = '$user_id' 

UNION ALL

SELECT NULL, 
       NULL, 
       NULL, 
       NULL,
       NULL,

       p.points_added AS points_added, 
       p.added_for AS added_for,
       p.date_added AS date_added
   FROM ap_user_points as p 
   WHERE p.user_id = '$user_id' ORDER BY date_earned DESC, date_added DESC;";

  $result8 = $conn->query($sql8);

        if ($result8->num_rows > 0) 
          // output data of each row
        while($row8 = $result8->fetch_assoc()) 


            ////// NOT SURE WHAT TO ECHO HERE? 

    

?>

【问题讨论】:

此代码似乎易受 SQL 注入攻击。将 prepared statementsbind placeholders 一起使用。如果您不能这样做,至少在将潜在不安全值 $user_id 包含在 SQL 中之前,通过 mysqli_real_escape_string 类型的函数运行它。怎么可能在 2015 年我们仍在编写如此明显易受 SQL 注入攻击的代码? 这只是一个粗略的示例代码,这还远未完成,我只需要添加一个关于如何检索结果的想法。我希望在生产前显着改善任何安全漏洞。 【参考方案1】:

向结果集中添加另一列。在该新列中,从两个查询中填充它...看起来它将是第一个查询中的 date_added 表达式和第二个查询中的 date_earned 表达式。当它们在同一列中时,排序很容易。 (这也假设这些表达式具有相同或兼容的数据类型,最好是 DATE、DATETIME 或 TIMESTAMP。)

然后您可以按序号位置排序,例如ORDER BY 2 按结果集中的第二列排序。

SELECT a1
     , b1
     , NULL
     , NULL
     , a1 AS sortexpr 
  FROM ...
 UNION ALL
SELECT NULL
     , NULL
     , x2
     , y2
     , x2 AS sortexpr
  FROM ...
 ORDER BY 5 DESC

这只是一种可能性。如果您无法添加额外的列来排列来自两个查询的表达式,那么您需要一种方法来区分哪个查询正在返回该行。我通常包含一个文字作为鉴别器列。

然后您可以使用隐式样式的 UNION 语法,将查询包装在括号中...

( SELECT 'q1' AS `source`
       , a1
       , b1   AS date_earned
       , NULL
       , NULL AS date_added
    FROM ...
)
UNION ALL
( SELECT 'q2'  AS `source`
       , NULL
       , NULL  AS date_earned
       , x2
       , y2    AS date_added
    FROM ...
 )
 ORDER BY IF(`source`='q1',date_earned,date_added) DESC

跟进

我可能误解了这个问题。我虽然问题是如何从以特定顺序返回的 UNION/UNION ALL 中获取行。

就我个人而言,我会编写查询以包含一个鉴别器列,然后尽可能多地排列这些列,以便对它们进行相同的处理。

举个例子:

SELECT 'reward'        AS `source`
     , r.date_earned   AS `seq`
     , r.user_id       AS `user_id` 
     , r.date_earned   AS `date_earned`
     , r.reward_id
     , r.reward
     , r.badge_desc
     , NULL            AS `points_added`  
     , NULL            AS `added_for`
  FROM r ...

 UNION ALL

SELECT 'points'        AS `source`
     , p.date_added    AS `seq`
     , p.user_id       AS `user_id`
     , p.date_added    AS `date_earned`
     , NULL
     , NULL
     , NULL
     , p.points_added  AS `points_added`
     , p.added_for     AS `added_for`
  FROM p ...

 ORDER BY 2 DESC, 1 DESC 

(实际上可能没有必要返回user_id,因为我们已经知道该值是什么。我在这里返回它是为了演示如何将两个结果集中的列“对齐”。)

然后,当我获取行时...

  if ( $row8['source'] == 'points' )  

      # process columns from a row of 'points' type
      echo $row8['badge_desc'];
      echo $row8['user_id'];

   elsif ( $row8['source'] == 'reward' )  

      # process columns from a row of 'reward' type
      echo $row8['added_for'];
      echo $row8['user_id'];

  

我会这样做的。

【讨论】:

那么使用这个系统,我将如何echo 我的结果以正确的顺序显示它们,如point, reward, point, point, reward, point,而不是像point, point, point, reward, reward, reward 这样的组,因为我知道我是否只是回显奖励或echo points_add 不行吗? 我想我误解了你的问题。我以为你在问如何在 SQL 中排序结果集。我将使用的方法是按照我希望它们呈现的顺序返回行,然后按照它们返回的顺序呈现它们。我会“排列”两个查询中的列。如果我有特殊处理,根据返回的查询以不同的方式处理行,我将使用一个鉴别器列,基于它的值,我将以一种方式处理来自一个来源的行,以及来自另一个来源的行另一种方法是选择要使用的列。

以上是关于使用 Union All 按日期顺序回显 SQL 数据的主要内容,如果未能解决你的问题,请参考以下文章

SQL union all 排序问题

SQL - 使用 Union All 和 Join 计算

按日期排序 UNION ALL 上的选择查询

UNION ALL 不回显附加文本[重复]

union all ,union 注意事项,查询结果集中的字段名称顺序必须一致

SQL Union和SQL Union All用法