Sql 规范化、聚合和联接表问题
假设我有一个客户数据库,他们购买的材料“适用于”随机对象。例如,John购买了10美元的适用于汽车和房子的“Material X”Sql 规范化、聚合和联接表问题,sql,sql-server,Sql,Sql Server,假设我有一个客户数据库,他们购买的材料“适用于”随机对象。例如,John购买了10美元的适用于汽车和房子的“Material X” Customers +----+-------+ | ID | Name | +----+-------+ | 1 | John | | 2 | Larry | +----+-------+ Orders +---------+------------+-------+----------+ | OrderID | CustomerID | Sales |
Customers
+----+-------+
| ID | Name |
+----+-------+
| 1 | John |
| 2 | Larry |
+----+-------+
Orders
+---------+------------+-------+----------+
| OrderID | CustomerID | Sales | Material |
+---------+------------+-------+----------+
| 1 | 1 | 10 | x |
| 2 | 1 | 15 | x |
| 3 | 1 | 6 | y |
| 4 | 2 | 3 | x |
| 5 | 2 | 25 | y |
+---------+------------+-------+----------+
我的材料
表原来是这样的
+----------+-------------------------+
| Material | Applicability |
+----------+-------------------------+
| x | car, house, plane, bike |
| y | car, bike |
+----------+-------------------------+
+----------+---------------+
| Material | Applicability |
+----------+---------------+
| x | car |
| x | house |
| x | plane |
| x | bike |
| y | car |
| y | bike |
+----------+---------------+
当我需要显示John购买的材料以及该材料适用于哪些对象时,我的查询如下
Select ID, Name, sum(Sales), Material, Applicability
FROM Customers a
INNER JOIN Orders b on a.ID = b.CustomerID
INNER JOIN Materials c on b.Material = c.Material
WHERE Name = 'John'
GROUP BY ID, Name, Material, Applicability
结果
+----+------+--------------+----------+-------------------------+
| ID | Name | Total Sales | Material | Applicability |
+----+------+--------------+----------+-------------------------+
| 1 | John | 25 | x | car, house, plane, bike |
| 1 | John | 6 | y | car, bike |
+----+------+--------------+----------+-------------------------+
逗号分隔的值(我知道它违反了许多规则)很方便,因为在解析适用性时,我可以简单地用逗号分隔字符串,然后我就有了一个适用性对象列表
现在决定规范化材质
表,所以现在看起来是这样的
+----------+-------------------------+
| Material | Applicability |
+----------+-------------------------+
| x | car, house, plane, bike |
| y | car, bike |
+----------+-------------------------+
+----------+---------------+
| Material | Applicability |
+----------+---------------+
| x | car |
| x | house |
| x | plane |
| x | bike |
| y | car |
| y | bike |
+----------+---------------+
这种规范化已经打乱了我现有的查询,它导致sum(sales)
结果是材料适用于多少对象的倍数
例如
+----+------+-------------+----------+---------------+
| ID | Name | Total Sales | Material | Applicability |
+----+------+-------------+----------+---------------+
| 1 | John | 25 | x | car |
| 1 | John | 25 | x | house |
| 1 | John | 25 | x | plane |
| 1 | John | 25 | x | bike |
| 1 | John | 6 | y | car |
| 1 | John | 6 | y | bike |
+----+------+-------------+----------+---------------+
现在看来约翰买了100美元的材料x,而实际上他只买了25美元。我需要向用户展示John购买的材料x,以及x的适用性
主要的问题是当我需要知道John买了什么,但也需要根据适用性进行筛选时
Select ID, Name, sum(Sales), Material, Applicability
FROM Customers a
INNER JOIN Orders b on a.ID = b.CustomerID
INNER JOIN Materials c on b.Material = c.Material
WHERE Name = 'John' and (applicability = 'car' or applicability = 'bike')
GROUP BY ID, Name, Material, Applicability
如果任何材料同时适用于汽车和自行车,则总价值sum(sales)
将加倍
如何处理这种重复?可能最简单的方法(对原始查询的修改最少)是先求和,然后加入适用性:
; with CTE as (
Select ID, Name, sum(Sales) as TotalSales, material
From Customers a
inner join orders b
on a.ID = b.CustomerID
group by ID, Name, Material
)
select b.*, c.Applicability from CTE b
inner join Materials c on b.Material = c.Material
where...--insert selection criteria here
希望这就是你想要的 请相应地标记您的数据库。你想要的结果和原来的一样吗?如果是这样,您希望使用类似于
group\u concat
的方法将行重新组合到单个列中…添加了sql server标记。是的,结果应该是一样的,唯一的区别是标准化的Materials表。Sql Server不支持组\u concat
。不过有几个例子说明了如何做到这一点。这有帮助吗:嗨,谢谢你的回答。如果我执行操作,则仍然返回重复的行,其中适用性='car'或适用性='house'
。如果有一种材质同时适用于这两种材质,它将返回两行。我认为mySql的group_concat的模拟会起作用,但我不确定。