将发票选项与原material 价格链接(历史表)

我无法在以下查询的倒数第二行使用发票i.DateSent,因为我收到以下错误.另外,如果有更好的方法来设计数据库/表的基础上,请让我知道,或者如果你有任何资源,我应该寻找,使我的概念更强大.谢谢!

错误:

Msg 4104, Level 16, State 1, Line 8
The multi-part identifier "i.DateSent" could not be bound.
Msg 4104, Level 16, State 1, Line 13
The multi-part identifier "i.DateSent" could not be bound.

-你在说什么?

SELECT i.InvoiceID, i.DateSent, io.InvoiceOptionID, i.Customer, RawMaterialA.Name AS RawMaterialA, RawMaterialA.Price AS PriceA, RawMaterialB.Name AS RawMaterialB, RawMaterialB.Price AS PriceB
FROM InvoiceOption io
FULL JOIN Invoice i ON io.InvoiceID = i.InvoiceID
LEFT JOIN (
    SELECT TOP 1 rm.RawMaterialID, rm.Name, rmp.Price, rmp.EffectiveDate
    FROM RawMaterial rm
    LEFT JOIN RawMaterialPrice rmp ON rm.RawMaterialID = rmp.RawMaterialID AND i.DateSent > rmp.EffectiveDate
) AS RawMaterialA ON io.RawMaterialAID = RawMaterialA.RawMaterialID
LEFT JOIN (
    SELECT TOP 1 rm.RawMaterialID, rm.Name, rmp.Price, rmp.EffectiveDate
    FROM RawMaterial rm
    LEFT JOIN RawMaterialPrice rmp ON rm.RawMaterialID = rmp.RawMaterialID AND i.DateSent > rmp.EffectiveDate
) AS RawMaterialB ON io.RawMaterialBID = RawMaterialB.RawMaterialID 

我想要的结果

InvoiceID   DateSent    InvoiceOptionID Customer    RawMaterialA    PriceA  RawMaterialB    PriceB
1   2023-12-01  101 Customer A  Material X  50.00   Material Y  30.00
1   2023-12-01  102 Customer A  Material X  50.00   Material Z  20.00

上下文: 假设我有一个表发票,它在InvoiceOption表中可以有多个选项.InvoiceOption取决于两种类型的原material A和B.但原material 价格可以改变,旧发票应该能够判断所用原material 的价格.为此,我基于以下条件使用原始material 价格的生效日期和发票的日期发送来联接InvoiceOption和原始material 价格表:(获取第一个价格where Invoice.DateSent>原始material 价格.EffectiveDate).生成数据和脚本的表格如下所示:

CREATE TABLE Invoice (
    InvoiceID INT PRIMARY KEY,
    Customer NVARCHAR(255),
    DateSent DATE,
    DateCreated DATE
);

-- Sample data
INSERT INTO Invoice (InvoiceID, Customer, DateSent, DateCreated)
VALUES
    (1, 'Customer A', '2023-12-01', '2023-11-28');

CREATE TABLE InvoiceOption (
    InvoiceOptionID INT PRIMARY KEY,
    InvoiceID INT,
    RawMaterialAID INT,
    RawMaterialBID INT,
    FOREIGN KEY (InvoiceID) REFERENCES Invoice(InvoiceID)
);

-- Sample data
INSERT INTO InvoiceOption (InvoiceOptionID, InvoiceID, RawMaterialAID, RawMaterialBID)
VALUES
    (101, 1, 101, 102),
    (102, 1, 101, 103);

CREATE TABLE RawMaterial (
    RawMaterialID INT PRIMARY KEY,
    Name NVARCHAR(255),
    Category NVARCHAR(50)
);

-- Sample data
INSERT INTO RawMaterial (RawMaterialID, Name, Category)
VALUES
    (101, 'Material X', 'Metal'),
    (102, 'Material Y', 'Wood'),
    (103, 'Material Z', 'Wood');

CREATE TABLE RawMaterialPrice (
    RawMaterialPriceID INT PRIMARY KEY,
    RawMaterialID INT,
    Price DECIMAL(10, 2),
    EffectiveDate DATE,
    FOREIGN KEY (RawMaterialID) REFERENCES RawMaterial(RawMaterialID)
);

-- Sample data
INSERT INTO RawMaterialPrice (RawMaterialPriceID, RawMaterialID, Price, EffectiveDate)
VALUES
    (1001, 101, 50.00, '2023-11-01'),
    (1002, 102, 30.00, '2023-11-01'),
    (1003, 103, 20.00, '2023-11-01'),
    (1004, 103, 10.00, '2023-10-01');

我试着询问Bing聊天,并理解我.DateSent可能超出了我创建的连接的范围,但无法生成有效的答案.

推荐答案

看起来您需要一个OUTER APPLY,因为这允许您在派生表中使用外部引用.联接条件需要作为WHERE推入内部

SELECT
  i.InvoiceID,
  i.DateSent,
  io.InvoiceOptionID,
  i.Customer,
  RawMaterialA.Name AS RawMaterialA,
  RawMaterialA.Price AS PriceA,
  RawMaterialB.Name AS RawMaterialB,
  RawMaterialB.Price AS PriceB
FROM InvoiceOption io
JOIN Invoice i ON io.InvoiceID = i.InvoiceID
OUTER APPLY (
    SELECT TOP (1)
      rm.RawMaterialID,
      rm.Name,
      rmp.Price,
      rmp.EffectiveDate
    FROM RawMaterial rm
    JOIN RawMaterialPrice rmp ON rm.RawMaterialID = rmp.RawMaterialID
    WHERE i.DateSent > rmp.EffectiveDate
      AND rm.RawMaterialID = io.RawMaterialAID
    ORDER BY rmp.EffectiveDate DESC
) AS RawMaterialA
OUTER APPLY (
    SELECT TOP (1)
      rm.RawMaterialID,
      rm.Name,
      rmp.Price,
      rmp.EffectiveDate
    FROM RawMaterial rm
    JOIN RawMaterialPrice rmp ON rm.RawMaterialID = rmp.RawMaterialID
    WHERE i.DateSent > rmp.EffectiveDate
      AND rm.RawMaterialID = io.RawMaterialBID
    ORDER BY rmp.EffectiveDate DESC
) AS RawMaterialB;

db<>fiddle

在某些情况下,您使用FULLLEFT联接的原因尚不清楚.正如前面提到的,它们可能应该是内部联接.

我还添加了一个ORDER BY,以使结果具有确定性.

Sql相关问答推荐

基于列对多行求和的查询

GROUP BY与多个嵌套查询T—SQL

Access中执行INSERT INTO查询时出现错误消息

如何在SQL中更新Json字符串

基于多参数的SQL Server条件过滤

按属性值 Select 数组元素Postgres Jsonb

按用户和时间列出的SQL Group考勤列表

此过程如何在不引用传递的参数值的情况下执行工作?

显示所有组并计算给定组中的项目(包括 0 个结果)

在 SQL Server 中查找重复项

获取上个月和上一年的值

如何对 jsonb 中的字段执行求和,然后使用结果过滤查询的输出

SQL Server - 判断 ids 层次 struct 中的整数 (id)

如何在 case 语句中使用聚合?

PostgreSQL中如何提取以特定字符开头的字符串中的所有单词?

正则表达式:停在第一个匹配的其中一个字符位置上

批量更改WooCommerce中所有产品的税收状态

如何防止 SQL 中的负收入值并将其重新分配到接下来的月份?

在 MySql 数据库中的两个日期之间搜索

SQL 查询以填充单个列中的所有值