我正在为我学校的午餐订单计划撰写报告,我已经提出了一个查询,它给了我需要的结果,但速度非常慢。我正在考虑使用相关的子查询来加速(来自另一个类似线程的建议)但是不能通过语法错误,甚至不确定它是否会实现我想要的。
涉及的两个表是Ordered_Items和Ordered_Options,Ordered Items表通常在Ordered Options表中有3-4个相关记录,表示学生在订购午餐时选择的选项。
典型的记录看起来像这样
Ordered_Items.Record_Number = 1
Ordered_Items.Name = Pizza
Ordered_Options.Ordered_Items_rn = 1
Ordered_Options.Value = Jane
Ordered_Options.rn = 43
Ordered_Options.Ordered_Items_rn = 1
Ordered_Options.Value = Doe
Ordered_Options.rn = 44
Ordered_Options.Ordered_Items_rn = 1
Ordered_Options.Value = Pepperoni
Ordered_Options.rn = 45
我希望它们全部显示为报告目的的单个记录,因此查询的输出看起来像:Pizza Jane Doe Pepperoni。 Ordered_Options.rn是一致的,意味着名字总是= 44,依此类推。我把我的代码放在下面。
SELECT
OI.Name AS ItemName,
opt1.`Value` AS StudentFirst,
opt2.`Value` AS StudentLast,
opt3.`Value` AS Grade,
opt4.`Value` AS Milk
FROM
((((
Ordered_Items OI
LEFT JOIN Ordered_Options opt1 ON ((
(OI.record_number = opt1.Ordered_Items_rn)
AND(opt1.Options_rn = 43))))
LEFT JOIN Ordered_Options opt2 ON((
(OI.record_number = opt2.Ordered_Items_rn)
AND(opt2.Options_rn = 44))))
LEFT JOIN Ordered_Options opt3 ON ((
(OI.record_number = opt3.Ordered_Items_rn)
AND(opt3.Options_rn = 46))))
LEFT JOIN Ordered_Options opt4 ON ((
(OI.record_number = opt4.Ordered_Items_rn)
AND(opt4.Options_rn = 55))))
答案 0 :(得分:3)
首先,正如其他人所说,如果你有可能真的修改数据库的结构,你现在拥有的东西没有多大意义。
然而,我一直在“必须从现有代码做报告”的情况,所以我知道你可能根本无法做到这一点;如果确实如此,那么以下查询应该可以帮助您显着提高速度:
SELECT
`Record_Number`,
Concat(Name, ' ', Group_Concat(Value ORDER BY rn ASC SEPARATOR ' ')) AS Request
FROM
`Ordered_Items` oi
LEFT OUTER JOIN `Ordered_Options` oo ON (oo.Ordered_Items_rn = oi.Record_Number)
GROUP BY
oi.Record_Number
哪个应该给你这样的东西:
Record_Number Request
1 Pizza Jane Doe Pepperoni
2 Fries Bobby Table French
由于你是新来的,请记住通过左侧的箭头来接受解决方案,这可以解决您的问题。如果没有,请在评论中说明原因。
我用过的示例数据库:
--
-- Table structure for table `Ordered_Items`
--
CREATE TABLE IF NOT EXISTS `Ordered_Items` (
`Record_Number` int(11) NOT NULL,
`Name` text NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
--
-- Dumping data for table `Ordered_Items`
--
INSERT INTO `Ordered_Items` (`Record_Number`, `Name`) VALUES
(1, 'Pizza'),
(2, 'Fries');
-- --------------------------------------------------------
--
-- Table structure for table `Ordered_Options`
--
CREATE TABLE IF NOT EXISTS `Ordered_Options` (
`Ordered_Items_rn` int(11) NOT NULL,
`Value` text NOT NULL,
`rn` int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
--
-- Dumping data for table `Ordered_Options`
--
INSERT INTO `Ordered_Options` (`Ordered_Items_rn`, `Value`, `rn`) VALUES
(1, 'Jane', 43),
(1, 'Doe', 44),
(1, 'Pepperoni', 45),
(2, 'Bobby', 43),
(2, 'Table', 44),
(2, 'French', 45);
答案 1 :(得分:2)
一些评论:
`
反复的习惯,这是一个眼睛。您只需要使用-gasp-空格来反对保留字或列名称。 ()
而不使用任何子选择,就不需要在此范围内使用AND
个括号。 关于你的桌子。
扔掉你现在拥有的那个并创建一个新表。
table ordered_item
-----------
id integer auto_increment primary key
item_id integer not null foreign key references item(id) on delete restrict on update cascade
customer_id integer not null foreign key references customer(id) on delete restrict on update cascade
qty integer not null
.....
table customer
--------------
id integer auto_increment primary key
firstname varchar(200)
.....
table item
----------
id integer auto_increment primary key
name varchar(200)
price decimal(10,2) //should really be in a separate table
以下查询将为每个订单提供订购的所有商品,并为客户1124提供总计。
SELECT customer.name, io.id as order_id, sum(io.qty) as number_of_items, i.*
FROM item i
INNER JOIN ordered_item oi ON (oi.item_id = i.id)
INNER JOIN customer c ON (c.id = oi.customer_id)
WHERE customer.id = '1124'
GROUP BY io.id WITH ROLLUP
这是SQL应该工作的方式,而不是你的方式。
顺便说一句,括号是可选的,我只是喜欢“为了便于阅读。”
答案 2 :(得分:1)
我同意使用适当的数据库结构会更容易,但如果您无法更改,我们会回答。我的答案类似于Lepidosteus',但是会在单独的列中为您提供值,而不是连接在一起。它以使用if运算符的子查询开始。
select oi.Record_Number as Record_Number, oi.Name as Name,
if (oo.rn = 43, oo.Value, null) as firstName,
if (oo.rn = 44, oo.Value, null) as lastName,
if (oo.rn = 45, oo.Value, null) as topping
from Ordered_Items as oi join Ordered_Options as oo
on oi.Record_Number = oo.Ordered_Items_rn;
这为Ordered_Items中的每个记录提供了一个包含多行的表,每个记录对Ordered_Options中的一个数据列具有正确的值,而在Ordered_Options的其他数据列中为null。
|Record_Number |Name |firstName |lastName |topping |
--------------------------------------------------------
|1 |Pizza |Jane |null |null |
|1 |Pizza |null |Doe |null |
|1 |Pizza |null |null |Pepperoni |
现在将此子查询包装在一个查询中,该查询将单个Ordered_Item行的所有记录组合在一起,并使用group_concat运算符从Ordered_Options中收集每个数据列的值(忽略空值)。
select c.Record_Number, c.Name,
group_concat(c.firstName) as firstName,
group_concat(c.lastName) as lastName,
group_concat(c.topping) as topping
from
(select oi.Record_Number as Record_Number, oi.Name as Name,
if (oo.rn = 43, oo.Value, null) as firstName,
if (oo.rn = 44, oo.Value, null) as lastName,
if (oo.rn = 45, oo.Value, null) as topping
from Ordered_Items as oi join Ordered_Options as oo
on oi.Record_Number = oo.Ordered_Items_rn) as c
group by c.Record_Number, c.Name;