SQL Server-左联接不起作用。因为?

时间:2018-09-06 08:03:21

标签: sql-server

这在MS Access中非常有效。 为什么不在MS SQL Server中?

你能帮我解决吗?

Here's how my query is

select * 
from tblPROestoque 
where idproduto = 8183
order by identrada desc

select top(1) * 
from tblPROestoque 
where idproduto = 8183
order by identrada desc

select *
from tblPROproduto pr
        left join (select top(1) idproduto, valcusto
                    from tblproestoque
                    order by identrada desc) tmp on tmp.idproduto = pr.idproduto
where pr.idproduto = 8183

2 个答案:

答案 0 :(得分:0)

我怀疑这里的问题是您对子查询如何工作的理解。我们有您的查询:

SELECT *
FROM tblPROproduto pr
     LEFT JOIN (SELECT TOP (1)
                       idproduto,
                       valcusto
                FROM tblproestoque
                ORDER BY identrada DESC) tmp ON tmp.idproduto = pr.idproduto
WHERE pr.idproduto = 8183;

我们可以将其分为两个不同的部分:

SELECT TOP (1)
       idproduto,
       valcusto
FROM tblproestoque
ORDER BY identrada DESC;

然后:

SELECT *
FROM tblPROproduto pr
     LEFT JOIN tmp ON tmp.idproduto = pr.idproduto
WHERE pr.idproduto = 8183;

这可能会向您解释为什么您的现有商品无法使用。我猜您在假设ON上的tmp子句是在子查询的SELECT之前派生的。事实并非如此。子查询将被派生,然后是ON。因此,tmp的值将是上面查询中返回的值。

我怀疑您想要的是什么

SELECT *
FROM tblPROproduto pr
     OUTER APPLY (SELECT TOP (1)
                       ca.idproduto,
                       ca.valcusto
                FROM tblproestoque ca
                WHERE ca.idproduto = pr.idproduto
                ORDER BY ca.identrada DESC) tmp
WHERE pr.idproduto = 8183;

编辑:为OP添加了一些示例数据和说明,以帮助其理解:

USE Sandbox;
GO

CREATE TABLE Product (ID int IDENTITY(1,1),
                      Sku varchar(10),
                      ProductName varchar(25));
CREATE TABLE ProductOrder (ID int IDENTITY(1,1),
                           ProductID int,
                           OrderDate date,
                           NumberOrdered int);

INSERT INTO dbo.Product (Sku,
                         ProductName)
VALUES ('65432462','Lawn Mower'),
       ('98742347','Helicopter'),
       ('89465735','BBQ');
INSERT INTO dbo.ProductOrder (ProductID,
                              OrderDate,
                              NumberOrdered)
VALUES (1,'20180101',7),
       (1,'20180708',19),
       (2,'20180501',12),
       (3,'20180804',27);
GO

SELECT *
FROM dbo.Product;
SELECT *
FROM dbo.ProductOrder;
GO

--Use the example the OP has in their post:
SELECT *
FROM dbo.Product P
     LEFT JOIN (SELECT TOP 1 *
                FROM dbo.ProductOrder
                ORDER BY OrderDate DESC) PO ON PO.ProductID = P.ID
WHERE P.ID = 2;
--This returns NULLs for all the latter columns.
--Why?
--Inspect the subquery:
SELECT TOP 1 *
FROM dbo.ProductOrder
ORDER BY OrderDate DESC;
--Product ID 3? 3 != 2 so the ON clause fails:
--Demonstrate
SELECT *
FROM dbo.Product P
     CROSS JOIN (SELECT TOP 1 * --CROSS JOIN joins all rows (creates a cartesian product)
                 FROM dbo.ProductOrder
                 ORDER BY OrderDate DESC) PO
WHERE P.ID = 2;
--The solution, use OUTER APPLY:
SELECT *
FROM dbo.Product P
     OUTER APPLY (SELECT TOP 1 *
                  FROM dbo.ProductOrder oa
                  WHERE oa.ProductID = P.ID --WHERE clause, this is like your ON
                  ORDER BY oa.OrderDate DESC) PO
WHERE P.ID = 2;
GO

DROP TABLE dbo.ProductOrder;
DROP TABLE dbo.Product;

答案 1 :(得分:0)

@RafaelBueno,您基本上需要一个outer apply。这在MSAcess中是不同的。

请参见以下修改内容:

让我知道它是否有效。

select *
from tblPROproduto pr
            outer apply (select top(1) idproduto, valcusto
                        from tblproestoque tmp
                        where tmp.idproduto = pr.idproduto
                        order by identrada desc) tmp 
where pr.idproduto = 8183