2017-02-14 4 views
1

У меня есть запрос, который использует столбец в выражении WHERE, но не возвращает этот столбец:Почему я должен включать столбец where where в группу, если я не возвращаю этот столбец в качестве результата ?, как я могу агрегировать повторяющиеся результаты?

SELECT 
    t1.upc, l1.description, l1.size, 
    l2.Name AS SectionName, l1.section, l3.Name, l1.department, 
    (SELECT SUM(QuantitySold) 
    FROM ProductMovement 
    JOIN ProductsMaster ON ProductsMaster.upc = ProductMovement.upc 
    WHERE TimeID >= (SELECT TimeID 
         FROM Time 
         WHERE FactDate = '1/14/2016') 
     AND TimeID <= (SELECT TimeID 
         FROM Time 
         WHERE FactDate = '1/14/2017') 
     AND ProductsMaster.upc = l1.upc 
     AND (l1.department = 4 OR l1.department = 13) 
     AND (t1.StoreID = 3 OR t1.StoreID = 9 OR t1.StoreID = 2)) AS Qty, 
    (SELECT SUM(TotalSales) 
    FROM ProductMovement 
    JOIN ProductsMaster ON ProductsMaster.upc = ProductMovement.upc 
    WHERE TimeID >= (SELECT TimeID 
         FROM Time 
         WHERE FactDate = '1/14/2016') 
     AND TimeID <= (SELECT TimeID 
         FROM Time 
         WHERE FactDate = '1/14/2017') 
     AND ProductsMaster.upc = l1.upc 
     AND (l1.department = 4 OR l1.department = 13) 
     AND (t1.StoreID = 3 OR t1.StoreID = 9 OR t1.StoreID = 2)) AS Sales 
FROM 
    ProductMovement t1 
JOIN 
    ProductsMaster l1 ON l1.upc = t1.upc 
JOIN 
    EnterpriseSections l2 ON l2.SectionID = l1.section 
JOIN 
    EnterpriseDepartments l3 ON l3.DepartmentID = l1.department 
WHERE 
    (SELECT SUM(QuantitySold) 
    FROM ProductMovement 
    JOIN ProductsMaster ON ProductsMaster.upc = ProductMovement.upc 
    WHERE TimeID >= (SELECT TimeID 
         FROM Time 
         WHERE FactDate = '1/14/2016') 
     AND TimeID <= (SELECT TimeID 
         FROM Time 
         WHERE FactDate = '1/14/2017') 
     AND ProductsMaster.upc = l1.upc 
     AND (l1.department = 4 OR l1.department = 13) 
     AND (t1.StoreID = 3 OR t1.StoreID = 9 OR t1.StoreID = 2)) IS NOT NULL 
GROUP BY 
    l1.upc, t1.upc, l1.section, l2.Name, l1.description, l1.size, l1.department, l3.Name 

Когда я запускаю это без t1.StoreID в пункте GROUP BY я получаю ошибку:

Column 'ProductMovement.StoreID' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.

Когда я добавляю столбец в группу, я получаю повторяющиеся результаты для каждого t1.storeID, потому что я все равно собираю все свои данные.

Почему мне нужно группировать столбец, который я не возвращаю, и как я могу суммировать эти результаты?

+0

Было бы полезно объяснить, чего вы пытаетесь достичь, предпочтительно включая диаграмму сущностей и отношений, описывающую взаимосвязь между многими таблицами, на которые вы ссылались. –

+0

Поскольку технически вы используете не только его в предложении WHERE вашего запроса, вы также используете его в предложении WHERE обоих ваших подкатегорий * Column *. Подзапросы столбцов имеют те же ограничения, что и сами столбцы. Попробуйте переместить 'SUM (..)' s из подзапросов в surrond и вместо этого содержать подзапросы. – RBarryYoung

ответ

0

Поскольку вы все равно собираете все данные, вы можете рассмотреть возможность использования двух запросов.

Первый запрос: включить все данные для магазинов 3, 9 и 2 в пределах диапазона дат. И сохраните это как временную таблицу.

Второй запрос: используйте временную таблицу в качестве входных данных. Но это в основном тот же запрос, что и вы, написанный выше, только без проверок для магазинов.

Обязательно оставляйте заметки людям, что данные являются совокупностью только этих 3 магазинов.

Разбивка на два этапа облегчит будущим программистам поиск этого кода, чтобы выяснить, что происходит.

Либо это или ... вы можете попробовать предложение HAVING вместо вашего окончания. WHERE статья.

SELECT t1.upc, l1.description, l1.size, l2.Name AS SectionName, l1.section, l3.Name, l1.department, 
    SUM(SELECT QuantitySold FROM ProductMovement JOIN ProductsMaster ON 
     ProductsMaster.upc = ProductMovement.upc 
      WHERE TimeID >= (SELECT TimeID FROM Time WHERE FactDate = '1/14/2016') 
      AND TimeID <= (SELECT TimeID FROM Time WHERE FactDate = '1/14/2017') 
      AND ProductsMaster.upc = l1.upc 
      AND (l1.department = 4 OR l1.department = 13) 
      AND (t1.StoreID = 3 OR t1.StoreID = 9 OR t1.StoreID = 2)) AS Qty, 
    SUM(SELECT TotalSales FROM ProductMovement JOIN ProductsMaster ON 
     ProductsMaster.upc = ProductMovement.upc 
     WHERE TimeID >= (SELECT TimeID FROM Time WHERE FactDate = '1/14/2016') 
      AND TimeID <= (SELECT TimeID FROM Time WHERE FactDate = '1/14/2017') 
      AND ProductsMaster.upc = l1.upc AND (l1.department = 4 OR l1.department = 13) 
      AND (t1.StoreID = 3 OR t1.StoreID = 9 OR t1.StoreID = 2)) AS Sales 
    FROM ProductMovement t1 
    JOIN ProductsMaster l1 ON l1.upc = t1.upc 
    JOIN EnterpriseSections l2 ON l2.SectionID = l1.section 
    JOIN EnterpriseDepartments l3 ON l3.DepartmentID = l1.department 
    GROUP BY l1.upc, t1.upc, l1.section, l2.Name, l1.description, l1.size, l1.department, l3.Name 
    HAVING SUM(SELECT QuantitySold FROM ProductMovement JOIN ProductsMaster ON 
      ProductsMaster.upc = ProductMovement.upc 
      WHERE TimeID >= (SELECT TimeID FROM Time WHERE FactDate = '1/14/2016') 
      AND TimeID <= (SELECT TimeID FROM Time WHERE FactDate = '1/14/2017') 
      AND ProductsMaster.upc = l1.upc 
      AND (l1.department = 4 OR l1.department = 13) 
      AND (t1.StoreID = 3 OR t1.StoreID = 9 OR t1.StoreID = 2)) IS NOT NULL 

Это будет проверить, если ваш Qty агрегат не Null послеGROUP BY завершена. (Вместо того, чтобы держать руку, как делает WHERE). Это более загруженный код и немного сложнее следовать. Если у вас небольшая база данных, я бы рекомендовал два решения для запросов. Если у вас есть огромная база данных, более широкий запрос может быть быстрее.

удачи :)

EDIT

Также поджать SUM функции вне выбирает вы имеете их. Так как вы не имеете GROUP BY внутри этих выбирает, вы не агрегирование их там. Вы агрегируете внешний выбор. Я изменю приведенный выше код, чтобы вывести функции SUM в основной запрос.

Хотя, я повторю ... разделение вашего запроса на два (как описано выше) позволит решить проблему, удалив StoreID из второго запроса.

+0

Спасибо, но этот запрос производит ту же ошибку: столбец «ProductMovement.StoreID» недопустим в списке выбора, потому что он не содержится ни в агрегатной функции, ни в предложении GROUP BY. – user3839756

+0

Ahhh yes ... Вполне возможно, что ваши функции 'SUM' должны находиться за пределами выбранных вами. Поскольку у вас нет' GROUP BY' внутри этих выборок, вы не собираете их там. Вы агрегируете внешний выбор. Я изменю приведенный выше код, чтобы вывести функции «СУММ» в основной запрос. (В качестве побочного примечания ... разделение вашего запроса на два разрешит проблему, удалив StoreID из второго запроса.) – abraxascarab

0

Why am I required to group by a column [ProductMovement.StoreID] I am not returning

Вы не можете возвращаться столбец, но для того, чтобы SQL-сервера, чтобы обработать Ваш запрос, он все равно будет необходимо загрузить его в память, потому что у вас в суб-запроса в вашем выбора пункта.Вот ваш запрос, и я опустил много деталей для краткости:

SELECT 
    t1.upc, l1.description, l1.size, 
    l2.Name AS SectionName, l1.section, l3.Name, l1.department, 
    (SELECT 
    WHERE 
     -- Here 
     (t1.StoreID = 3 OR t1.StoreID = 9 OR t1.StoreID = 2)) AS Qty, 
    (SELECT 
     -- Here 
     AND (t1.StoreID = 3 OR t1.StoreID = 9 OR t1.StoreID = 2)) AS Sales 
FROM 
    ProductMovement t1 
JOIN 
    ProductsMaster l1 ON l1.upc = t1.upc 
JOIN 
    EnterpriseSections l2 ON l2.SectionID = l1.section 
JOIN 
    EnterpriseDepartments l3 ON l3.DepartmentID = l1.department 
WHERE 
    (SELECT 
     -- Here 
     AND (t1.StoreID = 3 OR t1.StoreID = 9 OR t1.StoreID = 2)) IS NOT NULL 
GROUP BY 
    l1.upc, t1.upc, l1.section, l2.Name, l1.description, l1.size, l1.department, l3.Name 

Посмотрите на -- Here в приведенном выше запросе, чтобы увидеть, где вы ссылаетесь StoreID. SQL Server будет делать Group by, а затем Select, и поскольку предложение select ссылается на StoreId, SQL Server должен поддерживать колонку после Group by. Поскольку вы не использовали его в Group by или в агрегатной функции, он не знает, как с этим бороться: как он может группироваться по определенным столбцам в предложении Group by, если вы используете подзапрос в своем предложении select, который ссылается столбец, который не входит в группу?

0

Как правило, вы должны добавлять только столбцы, которые вы логически группируете в GROUP BY. Я предлагаю не использовать GROUP BY для уменьшения «случайных» дубликатов в вашем результирующем наборе, вызванном JOIN. Группировка по большим строковым значениям (что, по моему мнению, относится к продукции ProductMaster.Description), может привести к неоправданному снижению производительности.

Вот один способ, которым я рекомендовал бы достичь того, что я предположить вы пытаетесь сделать (в более короткий путь):

WITH Movement (
SELECT t1.upc, 
     SUM(t1.QuantitySold) AS 'QuantitySold', 
     SUM(t1.TotalSales) AS 'TotalSales' 
FROM ProductMovement t1 
WHERE t1.StoreID IN (2, 3, 9) 
    AND t1.TimeID >= (SELECT t.TimeID 
        FROM [Time] t 
        WHERE t.FactDate = '1/14/2016') 
    AND t1.TimeID <= (SELECT t.TimeID 
        FROM [Time] t 
        WHERE t.FactDate = '1/14/2017') 
    AND EXISTS (SELECT 1 
       FROM ProductsMaster l1 
       WHERE l1.upc = t1.upc 
       AND l1.department IN (4, 3)) 
GROUP BY t1.upc) 

SELECT m.upc, l1.[description], l1.size, 
     l2.[Name] AS 'SectionName', l1.section, l3.[Name], l1.department, 
     m.QuantitySold, 
     m.TotalSales 
FROM Movement m 
JOIN ProductsMaster l1 ON l1.upc = m.upc 
JOIN EnterpriseSections l2 ON l2.SectionID = l1.section 
JOIN EnterpriseDepartments l3 ON l3.DepartementID = l1.department; 

Опять же, это основано на множестве предположений, не зная сущности отношения. Однако он должен дать вам общую концепцию, которую я описываю.

0

Чтобы опираться на то, что сказал коддингши, , вы группируете внутренний агрегирование запросов по внешней ссылке запроса.

select * 
from t1 
inner join 
(select sum(value) 
from ProductMovement 
where (t1.StoreID = 3 OR t1.StoreID = 9 OR t1.StoreID = 2)) 

Ваш подзапрос имеет ссылку на внешний столбец. Это то же самое, как с помощью этого:

select * 
from t1 
cross join 
(select sum(value), StoreID 
from ProductMovement group by StoreID) as sQuery 
where (t1.StoreID = 3 OR t1.StoreID = 9 OR t1.StoreID = 2) 

Более вероятно, вам просто нужно изменить ваш где положение немного от этого:

AND ProductsMaster.upc = l1.upc 
    AND (l1.department = 4 OR l1.department = 13) 
    AND (t1.StoreID = 3 OR t1.StoreID = 9 OR t1.StoreID = 2)) IS NOT NULL 

к этому:

AND ProductsMaster.upc = l1.upc) 
    AND (l1.department = 4 OR l1.department = 13) 
    AND (t1.StoreID = 3 OR t1.StoreID = 9 OR t1.StoreID = 2) IS NOT NULL 

хотя Я не удивлюсь, если вам понадобится группа l1.upc для справки:

AND ProductsMaster.upc = l1.upc