使用 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 statements 与 bind 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 数据的主要内容,如果未能解决你的问题,请参考以下文章