Reputation: 67193
I could really use a little help with this query.
I have a Products
table.
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]
And a Transactions
table.
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])
And a CCTransactions
table.
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])
I need a query that UNION ALL
s all the Transactions
and CCTransactions
that fall within a given date range, and then groups them as Product.Id
, Product.Title
, SUM(Quantity)
, SUM(TotalAmount)
.
Below is what I have so far. It won't compile but I'm including because people usually want to see what you've tried. It tells me:
Msg 8120, Level 16, State 1, Line 5
Column 'Products.Id' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Msg 209, Level 16, State 1, Line 14
Ambiguous column name 'Id'.
I understand the errors, but am not sure the best way to fix them. The query seemed to be working before I added the union.
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
Upvotes: 2
Views: 6209
Reputation: 93161
You need 2 separate 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
Or a subquery:
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
Or you can rewrite the entire query:
;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
A note on CAST(t.[TimeStamp] AS DATE) <= @dtEnd
: this condition is not SARGable , meaning index and statistics are of no help. The result of CAST(t.[TimeStamp] AS DATE)
is not known until you have applied the function to each and every row. This causes a table scan (i.e. reading the entire table in) while you may only need a few rows. If Transactions
and CCTransactions
are huge, you will suffer.
Upvotes: 2
Reputation: 164099
First use UNION ALL for the 2 tables and join the result to Products:
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
Upvotes: 2