2016-08-02 3 views
2

Предположим, у меня есть база данных клиентов, которые покупают материалы, которые «применимы» к случайным объектам. Например, Джон покупает 10 долларов США «Материал X», который применим к машине и к дому.Выпуск нормализации, агрегации и объединения таблиц

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.

Основная проблема заключается в том, когда мне нужно выяснить, что Джон покупает, но также фильтрует по применимости.

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

Привет, спасибо за ответ. Это все равно возвращает повторяющиеся строки, если я делаю «где применимость =« автомобиль »или применимость =« дом ». Если есть один материал, который применим к обоим, он вернет две строки. Я думаю, что симуляция group_concat mySql будет работать, но я не уверен. –

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 

Будем надеяться, что это то, что вы ищете.

Смежные вопросы