如何正确地将TOP 1字段连接到SQL查询

时间:2014-08-14 16:32:21

标签: sql sql-server tsql sql-server-2012

如何正确地将注释块中的字段连接到SQL查询?我在订单标题上有一个结算电话号码,但在订单行上,每行都有一个发货电话号码。账单和运费可能不同。

在一个订单的每个订单行上,它是相同的发货号码的99%,但我想Top 1而不是group by只是因为某些数据搞砸了。

我认为UNION可能会得到我想要的东西,但似乎有一种更好的方法可以在一个查询中获取所有内容而不是复制&粘贴相同的“where”条款。

SELECT a.Order_no
       ,a.Customer_no
       ,a.BILL_LAST_NAME
       ,a.BILL_FIRST_NAME
       ,b.email
       ,a.BILL_ADDRESS1
       ,a.BILL_ADDRESS2
       ,a.BILL_CITY
       ,a.BILL_STATE
       ,a.BILL_POSTAL_CODE
       ,a.BILL_COUNTRY
       ,b.Address_Type
       ,a.BILL_PHONE
       ,a.BILL_PHONE_EXT
       ,a.Order_Date
       ,a.billing_status
       ,a.PO_Number
       ,a.Customer_comments
       ,a.ShipMethodShipperDesc
       ,a.ShipRate
       ,a.CouponDiscountCode
       ,a.CouponDiscount
       ,a.CustomerDiscount
       ,a.CustomerDiscountPercent
       ,a.SalesTaxTotal
       ,a.Payment_Method
       ,a.Credit_Card_Type
       ,a.Credit_Card_Number
       ,a.Order_Date
       ,a.BILL_TYPE
       ,a.Order_Net
       /* I added these lines but would like them joined properly */
       /*-------->*/
       , (select top 1 SHIP_ADDRESS1 from LineItems C where c.ORDER_NO = a.ORDER_NO)
       , (select top 1 SHIP_ADDRESS2  from LineItems C where c.ORDER_NO = a.ORDER_NO)
       , (select top 1 SHIP_CITY from LineItems C where c.ORDER_NO = a.ORDER_NO)
       , (select top 1 SHIP_STATE from LineItems C where c.ORDER_NO = a.ORDER_NO)
       , (select top 1 SHIP_POSTAL_CODE from LineItems C where c.ORDER_NO = a.ORDER_NO)
       , (select top 1 SHIP_COUNTRY from LineItems C where c.ORDER_NO = a.ORDER_NO)
       /*<-----------*/
FROM Orders AS a
       ,Customers AS b
WHERE a.customer_no = b.customer_no
       AND a.AccountName = 'mywebaccount'
       AND a.billing_status <> 'Canceled'
       AND a.transferred = 0
       AND a.order_status <> 'Canceled'
       AND EXISTS (
              SELECT *
              FROM LineItems c
              WHERE c.order_no = a.order_no
              )
ORDER BY a.order_date
       ,a.order_no

3 个答案:

答案 0 :(得分:1)

首先,不要FROM sometable1 AS t1, sometable2 AS t2。始终明确加入。其次,从您的案例看起来,APPLY的某些变体很适合。

这是我的版本:

SELECT a.Order_no
      ,a.Customer_no
      ,a.BILL_LAST_NAME
      ,a.BILL_FIRST_NAME
      ,b.email
      ,a.BILL_ADDRESS1
      ,a.BILL_ADDRESS2
      ,a.BILL_CITY
      ,a.BILL_STATE
      ,a.BILL_POSTAL_CODE
      ,a.BILL_COUNTRY
      ,b.Address_Type
      ,a.BILL_PHONE
      ,a.BILL_PHONE_EXT
      ,a.Order_Date
      ,a.billing_status
      ,a.PO_Number
      ,a.Customer_comments
      ,a.ShipMethodShipperDesc
      ,a.ShipRate
      ,a.CouponDiscountCode
      ,a.CouponDiscount
      ,a.CustomerDiscount
      ,a.CustomerDiscountPercent
      ,a.SalesTaxTotal
      ,a.Payment_Method
      ,a.Credit_Card_Type
      ,a.Credit_Card_Number
      ,a.Order_Date
      ,a.BILL_TYPE
      ,a.Order_Net
      ,li.SHIP_ADDRESS1
      ,li.SHIP_ADDRESS2
      ,li.SHIP_CITY
      ,li.SHIP_STATE
      ,li.SHIP_POSTAL_CODE
      ,li.SHIP_COUNTRY
FROM Orders AS a
INNER JOIN Customers AS b
    ON a.customer_no = b.customer_no
CROSS APPLY
(
    SELECT TOP 1 c.SHIP_ADDRESS1
                ,c.SHIP_ADDRESS2
                ,c.SHIP_CITY
                ,c.SHIP_STATE
                ,c.SHIP_POSTAL_CODE
                ,c.SHIP_COUNTRY 
    FROM LineItems c
    WHERE c.ORDER_NO = a.ORDER_NO
    ORDER BY c.Id -- or whatever
) AS li
WHERE a.AccountName = 'mywebaccount'
AND a.billing_status <> 'Canceled'
AND a.transferred = 0
AND a.order_status <> 'Canceled'
-- no need for that exists since CROSS APPLY works like INNER JOIN
ORDER BY a.order_date,a.order_no

答案 1 :(得分:0)

我建议像:

SELECT Order_no
       ,Customer_no
       ,BILL_LAST_NAME
       ,BILL_FIRST_NAME
       ... 
       ,SHIP_ADDRESS1
       ,SHIP_ADDRESS2
       ,SHIP_CITY
       ,SHIP_STATE
       ,SHIP_POSTAL_CODE
       ,SHIP_COUNTRY
FROM (

SELECT a.Order_no
       ,a.Customer_no
       ,a.BILL_LAST_NAME
       ,a.BILL_FIRST_NAME
       ,b.email
       ,a.BILL_ADDRESS1
       ,a.BILL_ADDRESS2
       ,a.BILL_CITY
       ,a.BILL_STATE
       ,a.BILL_POSTAL_CODE
       ,a.BILL_COUNTRY
       ,b.Address_Type
       ,a.BILL_PHONE
       ,a.BILL_PHONE_EXT
       ,a.Order_Date
       ,a.billing_status
       ,a.PO_Number
       ,a.Customer_comments
       ,a.ShipMethodShipperDesc
       ,a.ShipRate
       ,a.CouponDiscountCode
       ,a.CouponDiscount
       ,a.CustomerDiscount
       ,a.CustomerDiscountPercent
       ,a.SalesTaxTotal
       ,a.Payment_Method
       ,a.Credit_Card_Type
       ,a.Credit_Card_Number
       ,a.Order_Date
       ,a.BILL_TYPE
       ,a.Order_Net
       ,c.SHIP_ADDRESS1
       ,c.SHIP_ADDRESS2
       ,c.SHIP_CITY
       ,c.SHIP_STATE
       ,c.SHIP_POSTAL_CODE
       ,c.SHIP_COUNTRY
       , row_number() over (partition by a.order_no
                            order by SHIP_ADDRESS1, SHIP_ADDRESS2, SHIP_CITY, SHIP_STATE
                                   , SHIP_POSTAL_CODE, SHIP_COUNTRY) as rn
FROM Orders AS a
JOIN Customers AS b
    ON a.customer_no = b.customer_no
JOIN numberLineItems c
    ON c.order_no = a.order_no
WHERE a.AccountName = 'mywebaccount'
       AND a.billing_status <> 'Canceled'
       AND a.transferred = 0
       AND a.order_status <> 'Canceled'
) as x
WHERE rn = 1
ORDER BY order_date
       , order_no;

答案 2 :(得分:0)

我创建了一个简单的示例并发布了

HERE on SQL Fiddle

最简单的方法就是从子查询

加入前1名
select cus.*, ord.*, sub.*
from Customer cus
join [Order] ord on ord.CustomerId = cus.Id
join (
  select it.OrderId, it.ItemName, it.ItemAddress
  from Items it
  where it.Id in (select MAX(id) from Items group by OrderId)
  ) as sub on sub.OrderId = ord.Id 

如果你想看到第一个项而不是最后一个你可以用MIN(id)替换MAX(id)

注意唯一的问题&#34;如果订单没有项目,则表示没有显示。 但是如果您收到没有物品的订单但仍想显示它,您可以使用左连接

为一个正在运行的例子做个小提琴。

我希望你不介意我使用显式联接=)