【问题标题】:MYSQL UNION across 3 tables with ORDER BY使用 ORDER BY 跨 3 个表的 MYSQL UNION
【发布时间】:2012-06-18 21:36:21
【问题描述】:

我们有这样的声明:

(SELECT res_bev.bev_id, property_value.name AS priority 
    FROM res_bev, bev_property, property_value 
    WHERE res_bev.res_id='$resIn'
        AND bev_property.bev_id=res_bev.bev_id
        AND bev_property.type_id='23'
        AND property_value.id=bev_property.val_id)
UNION
(SELECT res_bev.bev_id, property_value.name as priority 
    FROM res_bev, bev_property, property_value 
    WHERE res_bev.res_id='$resIn' 
        AND bev_property.bev_id=res_bev.bev_id 
        AND bev_property.type_id='22' 
        AND property_value.id=bev_property.val_id)

我们有三张桌子:

Res_bev
res_id | bev_id |身份证

Bev_property
type_id | val_id | bev_id |身份证

属性值
姓名 |身份证

我正在寻找的是按玻璃价格(type_id='23')然后按瓶价格(type_id='22')订购的结果,但似乎联盟包含重复项,因为第一个选择返回说@ 987654323@,第二个返回3456 | 55,因为价格/玻璃是7.5,价格/瓶子是55; 如何从要返回的第二个 SQL 语句和有序表中消除这些重复项?

另外,通过左连接创建伪表以创建bev_id | price/Glass | price/Bottle 的表被愚弄了,但是由于这应该能够扩展到多种价格类型,我认为 UNION 会更有效。只需朝着正确的方向推动就会有所帮助。

【问题讨论】:

标签: php mysql


【解决方案1】:

您可以通过指定 bev_property.type_id 在 1 个查询中执行此操作,以匹配具有内部值的 IN() 子句。

要仅返回找到的第一个,您应该需要伴随字段 bev_idDISTINCT SELECT

要对它们进行排序,只需添加适当的降序 ORDER BY 子句。这应该首先排序,然后过滤出第二个 bev_property.type_id 值。 (数据库永远不会按特定顺序返回任何内容,除非您告诉他们这样做,有些可能有内部约定,或者看起来确实如此,但除非您在 SELECT 语句中指定 ORDER BY 子句,否则这永远不能保证是可重复的。 )

SELECT DISTINCT res_bev.bev_id, property_value.name AS priority 
FROM res_bev, bev_property, property_value 
WHERE res_bev.res_id='$resIn'
    AND bev_property.bev_id=res_bev.bev_id
    AND bev_property.type_id IN ('23','22')
    AND property_value.id=bev_property.val_id
ORDER BY bev_property.type_id DESC;

UNION 并不会真正更快,因为您必须进行两次整个查找,如果您没有对该字段进行索引,那么您将执行整个表遍历,匹配 1 个元素两次而不是执行与 2 个元素匹配的 1 个表遍历。 (遍历整张桌子通常很慢,不能将简单元素相互匹配)

如果索引正确,我认为执行新的选择查询和再次运行查询分析器可能会有一点开销,但我不确定。它可能足够聪明,可以识别查询之间的相似性,所以这无关紧要。

不过,尝试特定数据库并不总是有害的。每当您尝试将 query optimisation 与不同的语句一起使用时,将它们与 EXPLAIN 一起使用,这将向您显示查询将执行的操作以及它是否会遍历整个表、对文件中的数据进行排序等...

【讨论】:

  • 非常好,非常感谢您的解释 - 在我发布此内容并考虑之后,我认为会有比 UNION 更好的方法,尤其是在处理数千条记录时。然而,一个问题是,结果仍然没有正确排序 - Screen Shot - 正如你在那里看到的那样。它们应该完全是DESC,但似乎顺序被否定了......
  • 您在一个不可见的字段上订购,以确保在重复的情况下较高值的 (23) 胜出,也许您想订购 res_bev.bev_id 或 property_value.name也?那么按bev_property.type_id DESC、property_value.name DESC 大概排序?
  • 基本上如果你想影响它的输出顺序:通过参数添加额外的顺序。第一个的唯一目的是确保过滤掉正确的重复项。
  • 哦哦哦;明白了,我今晚会玩弄这个以达到 100% 并让每个人都知道我最终得到了什么;感谢一百万 @Harald 的帮助
  • 不要忘记您可以使用子选择来提供要订购的数据:所以 SELECT res_bev.bev_id, property_value.name AS priority FROM (our query here) c按优先级 DESC 排序;此过滤器首先过滤,然后获取结果并按照您的意愿对它们进行排序,而不会影响过滤器。它会慢一点,但不会慢很多。 :)
【解决方案2】:

除非我遗漏了什么,或者你有问题

SELECT res_bev.bev_id, 
       property_value.name AS priority 
FROM res_bev, bev_property, property_value 
WHERE res_bev.res_id='$resIn' 
AND bev_property.bev_id=res_bev.bev_id 
AND (bev_property.type_id='23' OR bev_property.type_id='22')
AND property_value.id=bev_property.val_id)
order by bev_property.type_id desc

PS 如果你想订购工会

尝试一些类似的东西

Select * from
(
select ...
Union
select ...
) somenameforqryinparentheses
Order by Somecolumn1, somecolumn2

【讨论】:

    猜你喜欢
    • 2014-05-30
    • 2016-11-22
    • 2014-10-03
    • 1970-01-01
    • 2017-11-02
    • 1970-01-01
    • 2011-12-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多