Объединяя UNION ALL с GROUP BY - PullRequest
       3

Объединяя UNION ALL с GROUP BY

2 голосов
/ 21 сентября 2019

Я мог бы действительно немного помочь с этим запросом.

У меня есть таблица Products.

CREATE TABLE [dbo].[Products](
    [Id] [int] NOT NULL,
    [Title] [nvarchar](50) NOT NULL,
    -- Additional column omitted
    CONSTRAINT [PK_Products] PRIMARY KEY CLUSTERED 
    (
        [Id] ASC
    ) ON [PRIMARY]
) ON [PRIMARY]

И таблица Transactions.

CREATE TABLE [dbo].[Transactions](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [ProductId] [int] NOT NULL,
    [TimeStamp] [datetime] NOT NULL,
    [Quantity] [decimal](9, 3) NOT NULL,
    [TotalAmount] [bigint] NOT NULL,
    -- Additional columns omitted
    CONSTRAINT [PK_Transactions] PRIMARY KEY CLUSTERED 
    (
        [Id] ASC
    ) ON [PRIMARY]
) ON [PRIMARY]

ALTER TABLE [dbo].[Transactions]  WITH CHECK ADD  CONSTRAINT [FK_Transactions_Products] FOREIGN KEY([ProductId])
REFERENCES [dbo].[Products] ([Id])

И таблица CCTransactions.

CREATE TABLE [dbo].[CCTransactions](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [ProductId] [int] NOT NULL,
    [TimeStamp] [datetime] NOT NULL,
    [Quantity] [decimal](9, 3) NOT NULL,
    [TotalAmount] [bigint] NOT NULL,
    -- Additional columns omitted
    CONSTRAINT [PK_CCTransactions] PRIMARY KEY CLUSTERED 
    (
        [Id] ASC
    )
) ON [PRIMARY]

ALTER TABLE [dbo].[CCTransactions]  WITH CHECK ADD  CONSTRAINT [FK_CCTransactions_Products] FOREIGN KEY([ProductId])
REFERENCES [dbo].[Products] ([Id])

Мне нужен запрос, который UNION ALL содержит все Transactions и CCTransactions, попадающие в заданный диапазон дат, а затем группирует их какProduct.Id, Product.Title, SUM(Quantity), SUM(TotalAmount).

Ниже приведено то, что я имею до сих пор.Это не скомпилируется, но я в том числе, потому что люди обычно хотят видеть то, что вы пробовали.Он говорит мне:

Сообщение 8120, Уровень 16, Состояние 1, Строка 5
Столбец «Products.Id» недопустим в списке выбора, поскольку он не содержится ни в статистической функции, ни впредложение GROUP BY.
Сообщение 209, Уровень 16, Состояние 1, Строка 14
Неоднозначное имя столбца 'Id'.

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

DECLARE @dtStart DATE = '2016-08-01';
DECLARE @dtEnd DATE = '2016-08-31';

SELECT p.Id, p.Title, SUM(t.Quantity), SUM(t.TotalAmount) AS Amount
FROM Transactions t
INNER JOIN Products p ON t.ProductId = p.Id
WHERE t.[TimeStamp] >= @dtStart AND CAST(t.[TimeStamp] AS DATE) <= @dtEnd
UNION ALL
SELECT p.Id, p.Title, SUM(t.Quantity), SUM(t.TotalAmount) AS Amount
FROM CCTransactions t
INNER JOIN Products p ON t.ProductId = p.Id
WHERE t.[TimeStamp] >= @dtStart AND CAST(t.[TimeStamp] AS DATE) <= @dtEnd
GROUP BY p.Id, p.Title
ORDER BY Title

Ответы [ 2 ]

2 голосов
/ 21 сентября 2019

Сначала используйте UNION ALL для 2 таблиц и объедините результат с:

DECLARE @dtStart DATE = '2016-08-01';
DECLARE @dtEnd DATE = '2016-08-31';

SELECT p.Id, p.Title, SUM(t.Quantity), SUM(t.TotalAmount) AS Amount
FROM (
  SELECT ProductId, [TimeStamp], Quantity, TotalAmount FROM Transactions
  UNION ALL
  SELECT ProductId, [TimeStamp], Quantity, TotalAmount FROM CCTransactions
) t INNER JOIN Products p ON t.ProductId = p.Id
WHERE t.[TimeStamp] >= @dtStart AND CAST(t.[TimeStamp] AS DATE) <= @dtEnd
GROUP BY p.Id, p.Title
ORDER BY Title
2 голосов
/ 21 сентября 2019

Вам нужно 2 отдельных GROUP BY s:

SELECT p.Id, p.Title, SUM(t.Quantity), SUM(t.TotalAmount) AS Amount
FROM Transactions t
INNER JOIN Products p ON t.ProductId = p.Id
WHERE t.[TimeStamp] >= @dtStart AND CAST(t.[TimeStamp] AS DATE) <= @dtEnd
GROUP BY p.Id, p.Title

UNION ALL

SELECT p.Id, p.Title, SUM(t.Quantity), SUM(t.TotalAmount) AS Amount
FROM CCTransactions t
INNER JOIN Products p ON t.ProductId = p.Id
WHERE t.[TimeStamp] >= @dtStart AND CAST(t.[TimeStamp] AS DATE) <= @dtEnd
GROUP BY p.Id, p.Title

Или подзапрос:

SELECT      X.id, X.Title, SUM(X.Quantity), SUM(X.TotalAmount)
FROM        (
                SELECT p.Id, p.Title, t.Quantity, t.TotalAmount
                FROM Transactions t
                INNER JOIN Products p ON t.ProductId = p.Id
                WHERE t.[TimeStamp] >= @dtStart AND CAST(t.[TimeStamp] AS DATE) <= @dtEnd

                UNION ALL

                SELECT p.Id, p.Title, t.Quantity, t.TotalAmount
                FROM CCTransactions t
                INNER JOIN Products p ON t.ProductId = p.Id
                WHERE t.[TimeStamp] >= @dtStart AND CAST(t.[TimeStamp] AS DATE) <= @dtEnd
            ) X
GROUP BY    X.Id, X.Title

Или вы можете переписать весь запрос:

;WITH
    AllTransaction AS
    (
        SELECT      ProductID, Timestamp, Quantity, TotalAmount
        FROM        Transaction
        UNION ALL
        SELECT      ProductID, Timestamp, Quantity, TotalAmount
        FROM        CCTransaction
    )

SELECT      p.Id, p.Ttitle, SUM(t.Quantity), SUM(t.TotalAmount)
FROM        AllTransaction      t
INNER JOIN  Products            p   ON t.ProductId = p.Id
WHERE       @dtStart <= t.[Timestamp] AND t.[TimeStamp] < DATEADD(DAY, 1, @dtEnd)
GROUP BY    p.Id, p.Title

Примечание по CAST(t.[TimeStamp] AS DATE) <= @dtEnd: это условие не SARGable , означающее, что индекс и статистика не помогают.Результат CAST(t.[TimeStamp] AS DATE) неизвестен, пока вы не применили функцию к каждой строке.Это вызывает сканирование таблицы (то есть чтение всей таблицы), в то время как вам может понадобиться всего несколько строк.Если Transactions и CCTransactions огромны, вы будете страдать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...