我尝试解决一段困扰我一段时间的MySQL查询问题。我只能使用脚本来解决这个问题,而不是单个查询,这有点烦人。
我有以下表格:
凭证: VoucherID,VoucherDate,姓名,地址......
Voucher_Item: VoucherItemID,VoucherID,ArticleNr,Amount,Price ......
由于表格可能会告诉您这是一个在线商店,我们这里有订单和订单文章,每个订单通过VoucherID链接为FK。所以我可以使用
SELECT ...
FROM Voucher v
LEFT JOIN Voucher_Item vi USING(VoucherID)
WHERE ...
到目前为止一切顺利。现在我的构造不好(我没有做到这一点,但我必须使用它),订单的邮资被视为一篇文章。
每个订单都有一个特定的,唯一的 - ArticleNr' ponat1'。
因此,每个订单至少包含一行或多行文章,其中可以包含" ArticleNr =' ponat1',此情况下的价格将包含邮资
这意味着邮资的订单如下:
Table Voucher:
VoucherID | VoucherDate | Name | Address ...
1 | 2017-01-11 | Mr. Harper | Sunset Boulevard 1100 ...
Table Voucher_Items:
VoucherItemID | VoucherID | ArticleNr | Amount | Price ...
1 | 1 | ponat1 | 1 | 5.00 //(Postage)
2 | 1 | 08343433 | 2 | 3.95 //(Any other article)
没有邮资的订单:
Table Voucher:
VoucherID | VoucherDate | Name | Address ...
2 | 2017-01-08 | Mr. Marc | Central Street 33 ...
Table Voucher_Items: //Note the misssing ArticleNr = 'ponat1' article as this order is postage free:
VoucherItemID | VoucherID | ArticleNr | Amount | Price ...
3 | 2 | 00548878 | 3 | 3.95 //(Any other article)
我的问题现在很简单:如何伪造查询以接收所有订单,包括使用
邮资WHERE ARticleNr = 'ponat1' OR ArticlenNr IS NULL
这里的一个大问题是ArticleNr实际上从不是NULL(因为其他文章总是存在),而是一条带有ArticleNr =' ponat1'如果订单是免邮费的话,根本就不存在,这意味着我的结果中缺少没有邮资的订单。我不想要的。
我希望他们在结果数组中使用0€邮资。
目前我总是要编写一个PHP脚本,或者提取所有订单,然后获取所有order_items并比较哪个订单没有带有nr' ponat1'将邮资设为0非常烦人。
我尝试了LEFT JOIN,RIGHT JOIN,UNION LEFT和RIGHT OUTER JOIN组合,并且没有找到可用的结果。 这甚至可以解决,还是桌面结构对这个问题不好?因为我个人认为凭证 - 邮资相当于1:1的关系,而且应该位于表格凭证中而不是单个字段,但正如我所说,我没有创建这个不幸的结构,我们无法改变,因为我们无法改变使用该表的系统结构
使用单个查询解决此问题会有很大帮助。
答案 0 :(得分:0)
您正在寻找的内容有点不清楚,因为您没有提供预期输出的任何示例。但是,修改示例查询,可以尝试以下操作:
SELECT ...
FROM Voucher v
LEFT JOIN Voucher_Item vi USING(VoucherID)
AND postage.ArticleNr <> 'ponat1'
LEFT OUTER JOIN Voucher_Item postage
ON postage.VoucherID = v.VoucherID
AND postage.ArticleNr = 'ponat1'
WHERE ...
使用上述结构,您可以将邮资物品与其他物品分开。只需从邮资别名表中选择,检查它是否为空或有价格。
请注意,这将为Voucher_Item表中的每条记录返回一行,如果没有非邮资项,则Voucher_Item数据将为null。如果每个凭证记录只需要一行,则需要包含有关所需信息的更多信息。那时候可能需要GROUP BY。
答案 1 :(得分:0)
您可以做的是添加一个项目(在您的邮件中邮资),该项目已添加到所有优惠券中;
INSERT INTO Voucher_Item VALUES (4, 0, 'ponat1', 0, 0.00);
请注意,此项目VoucherID
为0
。
否则
SELECT v.VoucherID, vi.*
FROM Voucher v LEFT JOIN Voucher_Item vi
ON v.VoucherID = vi.VoucherID OR vi.VoucherID = 0
ORDER BY v.VoucherID;
将导致
VoucherID VoucherItemID VoucherID ArticleNr Amount Price
1 2 1 08343433 2 3.95
1 4 0 ponat1 0 0
1 1 1 ponat1 1 5
2 3 2 00548878 3 3.95
2 4 0 ponat1 0 0
所以我们几乎就在那里,只有带邮资的优惠券,现在有两次邮资。幸运的是,由于邮资金额和默认邮资的价格为0,我们可以简单地按商品编号分组,并对金额和价格进行总结。
SELECT vi.VoucherItemId, v.VoucherID, vi.ArticleNr,
SUM(vi.Amount) AS Amount, SUM(vi.Price) AS Price
FROM Voucher v LEFT JOIN Voucher_Item vi
ON v.VoucherID = vi.VoucherID OR vi.VoucherID = 0
GROUP BY v.VoucherID, vi.ArticleNr
ORDER BY v.VoucherID, vi.VoucherItemID;
哪个结果
VoucherItemID VoucherID ArticleNr Amount Price
1 1 ponat1 1 5
2 1 08343433 2 3.95
3 2 00548878 3 3.95
4 2 ponat1 0 0
编辑以澄清现有软件未受影响且现有数据无需更改:
要实施此解决方案,您只需要在Voucher_Item
中插入1条记录,该记录将适用于所有凭证(过去和将来创建)。
此外,如果它不会影响当前软件,因为运行现有查询将返回没有添加邮资记录的记录
SELECT vi.*
FROM Voucher v INNER JOIN Voucher_Item vi
ON v.VoucherID = vi.VoucherID
ORDER BY v.VoucherID, vi.VoucherItemID;
仍会返回
VoucherItemID VoucherID ArticleNr Amount Price
1 1 ponat1 1 5
2 1 08343433 2 3.95
3 2 00548878 3 3.95
答案 2 :(得分:0)
如果我理解正确,您希望在没有邮资行时添加其他(虚拟)行。您可以使用union
:
SELECT ...
FROM
(select v.*,
vi.VoucherItemID, vi.ArticelNr, vi.Amount, vi.Price
FROM Voucher v
LEFT JOIN Voucher_Item vi -- maybe not a left join?
on v.VoucherId = vi.VoucherID
UNION -- use "union all" if v.* is not unique
SELECT v.*,
null as VoucherItemID, 'ponat1' as ArticleNr, 1 as Amount, 0 as Price
FROM Voucher v
WHERE not exists
(select 1 from Voucher_Item vi
where v.VoucherID = vi.VoucherID
and vi.ArticleNr = 'ponat1')
) as v_compl
WHERE ...
它将接受所有订单,并为每个凭证添加一行,但找不到'ponat1'
- 行。 (VoucherID, ArticleNr)
上的索引会有所帮助。您可能希望为该子查询创建一个视图,或者按原样使用它。
它不会重新计算VoucherItemID
(可能是自动增量字段)。如果您也需要,可以添加另一个图层并计算行号,例如使用负行号作为VoucherItemID
或添加足够高的偏移量以使其唯一。
我不确定为什么在“每个订单至少包含一行或多行文章”时使用left join
,但为了完整性,请注意此查询还会向有优惠券的凭证添加一行根本没有任何物品。