【问题标题】:T-SQL Left-Join with 1 row (limi, subselect)T-SQL 左连接 1 行(limi,子选择)
【发布时间】:2014-04-08 01:29:57
【问题描述】:

我已经阅读了很多关于该主题的内容,但我无法让它适用于我的案例。

我有以下情况:

  • 订单项列表(我要获取的主要数据集)
  • 与订单项具有 1:1 关系的文章
  • 一个 n:m 可连接的“Articlesupplier”,它在文章和文章之间创建关系 合作伙伴
  • 包含合作伙伴详细信息的合作伙伴表。

目标:
每个 OrderItem 和来自供应商的一个数据集我只想获得在连接中找到的第一个数据集。不需要优先级。

表格:

IDX_ORDERITEM

id,article_id

IDX_ARTICLE

id,name

IDX_ARTICLESUPPLIER

article_id,partner_id

IDX_PARTNER

id,abbr

我的实际陈述(简短版):

SELECT IDX_ORDERITEM.id
FROM         
dbo.IDX_ORDERITEM AS IDX_ORDERITEM

-- ARTICLE --
INNER JOIN dbo.IDX_ARTICLE AS IDX_ARTICLE
ON IDX_ORDERITEM.article_id=IDX_ARTICLE.id

-- SUPPLIER VIA ARTICLE --  
LEFT JOIN 
  (SELECT TOP(1) IDX_PARTNER.id, IDX_PARTNER.abbr 
  FROM IDX_PARTNER, IDX_ARTICLESUPPLIER
  WHERE IDX_PARTNER.id = IDX_ARTICLESUPPLIER.partner_id
  AND IDX_ARTICLESUPPLIER.article_id=IDX_ARTICLE.id) AS IDX_PARTNER_SUPPLIER 
  ON IDX_PARTNER_SUPPLIER.id=IDX_ARTICLE.supplier_partner_id

WHERE 1>0
ORDER BY orderitem.id DESC

但似乎我无法在子查询中访问 IDX_ARTICLE.id。我收到以下错误消息:

无法绑定多部分标识符“IDX_ARTICLE.id”。

是文章别名与表名同名的问题吗?

非常感谢您提供可能的想法, 迈克

【问题讨论】:

  • 将您的表称为IDX_...... 是一个非常不幸、错误的命名约定 - 直观上指的是 索引 - 而不是表!
  • 你是对的,但不幸的是,这不是我的数据库,ERP 系统的名称是“IDX”,这就是这种命名约定的原因。

标签: sql sql-server tsql join left-join


【解决方案1】:

好吧,我更改了您的别名,以及您要加入的子查询(我还修改了该子查询,因此它不再使用隐式连接),尽管这主要是化妆品的变化。真正重要的变化是使用OUTER APPLY 而不是LEFT JOIN

SELECT OI.id
FROM dbo.IDX_ORDERITEM AS OI
INNER JOIN dbo.IDX_ARTICLE AS A
    ON OI.article_id = A.id
OUTER APPLY  
  (SELECT TOP(1) P.id, P.abbr 
   FROM IDX_PARTNER AS P
   INNER JOIN IDX_ARTICLESUPPLIER AS SUP
        ON P.id = SUP.partner_id
   WHERE SUP.article_id = A.id
   AND P.id = A.supplier_partner_id) AS PS 
ORDER BY OI.id DESC

【讨论】:

    【解决方案2】:

    由于以下查询而引发错误

     (SELECT TOP(1) IDX_PARTNER.id, IDX_PARTNER.abbr 
      FROM IDX_PARTNER, IDX_ARTICLESUPPLIER
      WHERE IDX_PARTNER.id = IDX_ARTICLESUPPLIER.partner_id
      AND IDX_ARTICLESUPPLIER.article_id=IDX_ARTICLE.id) AS IDX_PARTNER_SUPPLIER 
    

    不能被视为相关子查询,IDX_ARTICLE.id 在其中引用的方式与我们在相关子查询中引用外部查询字段的方式相同。

    【讨论】:

      【解决方案3】:

      我发现了两个问题。

      根据您的 DDL,没有您在左侧连接子句中引用的 IDX_ARTICLE.supplier_partner_id。

      其次,我很确定您不能在派生表中使用 IDX_ARTICLE.id。只需将 IDX_ARTICLESUPPLIER.article_id 添加到派生表的选定字段中,然后在针对 IDX_ARTICLE.id 的左连接子句中使用它。

      【讨论】:

        【解决方案4】:

        我更喜欢避免嵌套查询。如果可以的话,我会一直用 CTE 重写它。

        WITH    Part_Sup
                  AS (
                       SELECT TOP ( 1 ) P.id
                           ,P.abbr
                           ,SUP.article_id
                        FROM IDX_PARTNER AS P
                        INNER JOIN IDX_ARTICLESUPPLIER AS SUP
                            ON P.id = SUP.partner_id
                     )
            SELECT OI.id
                FROM dbo.IDX_ORDERITEM AS OI
                INNER JOIN dbo.IDX_ARTICLE AS A
                    ON OI.article_id = A.id
                LEFT OUTER JOIN Part_Sup AS PS
                    ON PS.article_id = A.Id
                       AND PS.id = A.supplier_partner_id
                ORDER BY OI.id DESC;
        

        接下来我重写了第一个查询以使用ROW_NUMBER() 函数而不是使用TOP (1) 使用ROW_NUMBER 您可以控制您想要哪些结果以及您不想要哪些结果。

        WITH    Part_Sup
                  AS (
                       SELECT P.id
                           ,P.abbr
                           ,SUP.article_id
                           ,ROW_NUMBER() OVER ( PARTITION BY P.id, P.abbr ) AS RowNum
                        FROM IDX_PARTNER AS P
                        INNER JOIN IDX_ARTICLESUPPLIER AS SUP
                            ON P.id = SUP.partner_id
                     )
            SELECT OI.id
                FROM dbo.IDX_ORDERITEM AS OI
                INNER JOIN dbo.IDX_ARTICLE AS A
                    ON OI.article_id = A.id
                LEFT OUTER JOIN Part_Sup AS PS
                    ON PS.article_id = A.Id
                       AND PS.id = A.supplier_partner_id
                       AND RowNum = 1
                ORDER BY OI.id DESC;
        

        【讨论】:

          【解决方案5】:

          感谢 Lamak - 你解决了它 :) 我使用您的输入来提取基本解决方案,以便其他有相同问题的人更容易阅读:

          使用 OUTER APPLY(此处没有 ORDER_ITEM 表):

          SELECT IDX_ARTICLE.id AS AR_ID, IDX_PARTNER_SUPPLIER.id, IDX_PARTNER_SUPPLIER.abbr
          FROM         
          dbo.IDX_ARTICLE AS IDX_ARTICLE
          
          OUTER APPLY
              (SELECT TOP(1) _PARTNER.id, _PARTNER.abbr
              FROM IDX_PARTNER AS _PARTNER
              INNER JOIN IDX_ARTICLESUPPLIER AS _ARTICLESUPPLIER
                  ON _PARTNER.id = _ARTICLESUPPLIER.partner_id
              WHERE _ARTICLESUPPLIER.article_id=IDX_ARTICLE.id
              AND _ARTICLESUPPLIER.deleted IS NULL) AS IDX_PARTNER_SUPPLIER
          
          WHERE IDX_ARTICLE.id=67
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-06-23
            • 1970-01-01
            • 1970-01-01
            • 2017-09-18
            • 1970-01-01
            • 2012-12-09
            相关资源
            最近更新 更多