2016-08-02 28 views
2

比方說,我有一個客戶的數據庫,他們購買對隨機對象「適用」的材料。例如,約翰購買了適用於汽車和房屋的「材料X」中的10美元。標準化,彙總和連接表問題

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  | 
+---------+------------+-------+----------+ 

Materials表原本看上去像這樣

+----------+-------------------------+ 
| Material |  Applicability  | 
+----------+-------------------------+ 
| x  | car, house, plane, bike | 
| y  | car, bike    | 
+----------+-------------------------+ 

當我需要顯示什麼材料約翰和購買的對象是材料適用於,我的查詢是這樣的。

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    | 
+----+------+--------------+----------+-------------------------+ 

的逗號分隔值(我知道這違反了很多規則)很方便,因爲分析的適用性時,我可以簡單地劃分用逗號的字符串,然後我有一個列表適用性對象。

現在,它已經決定正常化Materials表,所以現在它看起來像這樣

+----------+---------------+ 
| 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)將增加一倍。

我該如何處理這種重複?

+0

請相應地標記您的數據庫。你想要的結果是什麼,和原來的一樣?如果是這樣,你想使用像'group_concat'這樣的行重新組合成一列... – sgeddes

+0

添加了sql-server標籤。是的結果應該是相同的,唯一的區別是規格化的材料表。 –

+0

Sql Server不支持'group_concat'。 SO有幾個例子,但是如何做到這一點。這有助於:http://stackoverflow.com/questions/451415/simulating-group-concat-mysql-function-in-sql-server – sgeddes

回答

0

這可能是最簡單的(至少修改原始查詢)只是第一和,再加入上的適用性算賬:

; 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 
+0

嗨,謝謝你的答案。這仍然返回重複的行,如果我做'適用性='汽車'或適用性='家''。如果有一種適用於兩者的材料,它將返回兩行。我認爲模擬mySql的group_concat會起作用,但我不確定。 –

0
SELECT 'x' as Material  , 'car' as Applicability   
INTO #Materials 
UNION ALL 
SELECT 'x'  , 'house'   
UNION ALL 
SELECT 'x'  , 'plane'  
UNION ALL 
SELECT 'x'  , 'bike'   
UNION ALL 
SELECT'y'  , 'car'   
UNION ALL 
SELECT 'y'  , 'bike' 





SELECT 1 as OrderID ,   1 as CustomerID, 10 as Sales, 'x' as Material 
INTO #Orders 
UNION ALL 
SELECT 2 ,   1 , 15 , 'x'   
UNION ALL 
SELECT 3 ,   1 ,  6 , 'y'   
UNION ALL 
SELECT 4 ,   2 ,  3 , 'x'   
UNION ALL 
SELECT 5 ,   2 , 25 , 'y'   



SELECT 1 as ID , 'John' as Name 
INTO #Customers 
UNION ALL 
SELECT 2 , 'Larry'; 
with CTE as (
SELECT ID, Name, sum(Sales) as TotalSales, c.material, Applicability 
From #Customers a 
inner join #orders b 
on a.ID = b.CustomerID 
inner join #Materials as c on c.Material = b.Material 
where Name = 'John' and (applicability = 'car' or applicability = 'house') 
group by ID, Name, c.Material, Applicability 
) 


SELECT ID, Name, TotalSales, Material, STUFF(
(SELECT distinct ',' + Applicability 
FROM cte as c 
where c.Material = c1.Material 

FOR XML PATH ('')) 
, 1, 1, '') as Applicability 
from CTE c1 
group by ID, Name, TotalSales, Material 

drop table #Customers 
drop table #Orders 
drop table #Materials 

我們希望,這是你在尋找什麼。