Show totals in last row of query - sql

I would like to show the totals of the last 2 columns but can't seam to get the right code.
Here is the code.
declare #FromDate as datetime
declare #ToDate as datetime
set #FromDate='1/1/2018'
set #ToDate='1/31/2018'
Select
OrderMain.OrderNumber,
OrderMain.OrderDate,
OrderMain.TotalMiles,
OFAddStop.FeeValue AS NumberStops
From
Ordermain with (readuncommitted)
Left Outer Join Customer with (readuncommitted) on Ordermain.CustomerID=Customer.CustomerID
Left outer join OrderFee OFAddStop with (readuncommitted) on OFAddStop.OrderID=OrderMain.OrderID
and OFAddStop.Sequence=9 and OFAddStop.SubSequence=6
Where
Customer.CustomerCode IN('36716')
and OrderMain.OrderDate >=#FromDate
and OrderMain.OrderDate <=#ToDate
and OrderMain.OrderStatus in ('N','A','I','P')
Here is an example of the Query
OrderNumber OrderDate TotalMiles NumberStops
10747511 01/02/18 280 6
10750287 01/03/18 118 4
The last row should look like this
OrderNumber OrderDate TotalMiles NumberStops
10747511 01/02/18 280 6
10750287 01/03/18 118 4
Total 398 10
Can someone show me the correct way to make this happen?

In SQL Server, you can do this using GROUPING SETS, but you need an aggregation query:
Select om.OrderNumber, om.OrderDate,
SUM(om.TotalMiles) as TotalMiles,
SUM(oaf.FeeValue) as NumberStops
From Ordermain om Join
Customer c
on om.CustomerID = c.CustomerID Left outer join
OrderFee oaf
on oaf.OrderID = om.OrderID and
oaf.Sequence = 9 and oaf.SubSequence = 6
Where c.CustomerCode in ('36716') and
om.OrderDate >= #FromDate
om.OrderDate <= #ToDate and
om.OrderStatus in ('P', 'A', 'I', 'N') -- couldn't resist
group by grouping sets ( (om.OrderNumber, om.OrderDate), () );
Notes:
Table aliases make the query easier to write and to read.
The aggregation is on the first two columns. I presume there are no duplicates for those.
You are looking for a specific customer, so the join to that table should be a regular join.

If the db accepts With clause.
declare #FromDate as datetime
declare #ToDate as datetime
set #FromDate='1/1/2018'
set #ToDate='1/31/2018'
With
records as (
Select
cast(OrderMain.OrderNumber as varchar(32)) OrderNumber,
OrderMain.OrderDate,
OrderMain.TotalMiles,
OFAddStop.FeeValue AS NumberStops
From
Ordermain with (readuncommitted)
Left Outer Join Customer with (readuncommitted) on
Ordermain.CustomerID=Customer.CustomerID
Left outer join OrderFee OFAddStop with (readuncommitted) on
OFAddStop.OrderID=OrderMain.OrderID
and OFAddStop.Sequence=9 and OFAddStop.SubSequence=6
Where
Customer.CustomerCode IN('36716')
and OrderMain.OrderDate >=#FromDate
and OrderMain.OrderDate <=#ToDate
and OrderMain.OrderStatus in ('N','A','I','P')
)
Select
OrderNumber,
OrderDate,
TotalMiles,
NumberStops
From
records
Union All
Select
'Total',
null,
sum(TotalMiles),
sum(NumberStops)
From
records

Related

Advanced SQL: Sum of sales between a date range

I'm trying to get the sum of sales for a specific product between a date range. Unfortunately, the sum of sales from the results for both dates are the same. By right the total sales on 2019/01/01 is 5000 and the total sales on following day 2019/01/02 is 3000. The results showed total sales which is 8000 for both days. Which is wrong. Any expert can help to improve is this query?
Declare #BusinessDate datetime ='2019-01-01'
Declare #end datetime ='2019-01-02'
DECLARE #StoreId int = 100
SELECT [Terminals].[Id] AS [TerminalId],
[Terminals].[StoreId],
[EOD].[Id] AS [EODId],
SUM([Sales].[SalesAmount]) AS [SalesAmount],
[EOD].BusinessDate
FROM [CEPP]..[Stores] WITH (NOLOCK)
INNER JOIN [CEPP]..[Terminals] WITH (NOLOCK)
ON [Stores].[Id] = [Terminals].[StoreId]
AND [Terminals].[MWorkFlowStatusId] = 2
AND ([Terminals].[MStatusId] = 1
OR ([Terminals].[MStatusId] = 0
AND [Terminals].[SuspendedDate] > #BusinessDate ))
LEFT JOIN [EndOfDays] AS [EOD] WITH (NOLOCK)
ON [Terminals].[Id] = [EOD].[TerminalId]
AND [EOD].[BusinessDate] >= #BusinessDate and [EOD].[BusinessDate]<=#end
CROSS APPLY (
SELECT SUM([Products].[Deno]) AS [SalesAmount]
FROM [SalesOrders] AS [SO] WITH (NOLOCK)
INNER JOIN [SalesTransactions] AS [ST] WITH (NOLOCK)
ON [SO].[Id] = [ST].[SalesOrderId]
LEFT JOIN [VoidOrders] AS [VO] WITH (NOLOCK)
INNER JOIN [VoidTransactions] AS [VT] WITH (NOLOCK)
ON [VO].[Id] = [VT].[VoidOrderId]
ON [SO].[DealerId] = [VO].[DealerId]
AND [SO].[StoreId] = [VO].[StoreId]
AND [SO].[TerminalId] = [VO].[TerminalId]
AND [ST].[ProductId] = [VT].[ProductId]
AND [ST].[SerialNo] = [VT].[SerialNo]
AND [ST].[BusinessDate] = [VT].[BusinessDate]
AND [VT].[MVoidTypeId] = 1
INNER JOIN [CEPP].[dbo].[Products] WITH (NOLOCK)
ON [ST].[ProductId] = [Products].[Id]
WHERE [EOD].[Id] IS NOT NULL
AND [VT].[SerialNo] IS NULL
AND [SO].[TerminalId] = [Terminals].[Id]
AND [ST].[BusinessDate] >= #BusinessDate and [ST].[BusinessDate] <= #end
) AS [Sales]
WHERE [Stores].[DealerId] = 1 AND (#StoreId IS NULL OR [Terminals].[StoreId] = #StoreId)
GROUP BY [Terminals].[Id], [Terminals].[StoreId], [EOD].[Id], [Stores].[Code], [Terminals].[Code],[EOD].BusinessDate
ORDER BY ISNULL([EOD].[Id], 0), [Stores].[Code], [Terminals].[Code]
The unexpected results I got is :
TerminalId StoreId EODId SalesAmount BusinessDate
21598 100 5427531 8000.00 2019-01-01 00:00:00.000
21598 100 5427532 8000.00 2019-01-02 00:00:00.000
The results should be like this:
TerminalId StoreId EODId SalesAmount BusinessDate
21598 100 5427531 5000.00 2019-01-01 00:00:00.000
21598 100 5427532 3000.00 2019-01-02 00:00:00.000
From what I can see at a glance and without test data, is that the SUM([Products].[Deno]) is being performed in the CROSS APPLY irrespective of any GROUP BY you have in the outer query. Hence why you're getting SUM([Sales].[SalesAmount]) to equal 8000 for each output row.
Refactor the CROSS APPLY subquery to aggregate SUM([Products].[Deno]) with respect to a GROUP BY and join back to the main table by the GROUP BY predicates to your outer query.
AND [EOD].[BusinessDate] >= #BusinessDate and [EOD].[BusinessDate]<=#end
This part looks very suspicious to me. I think it should be something like
[EOD].[BusinessDate] = [Sales].[Date]
If that does not resolve your problem, please provide us with scripts for creation of tables and test data. That way it's much easier to investigate query.

SQL Select Where Between statement missing results that should be there?

I apologize if this question has already been asked, but I couldn't find anything on it.
Basically, my accounting department runs a report every month to pull up all orders from a specific client for the previous month. My problem is that I have orders that are not showing up in these reports. The only similarities I can find in the orders that are missing is that if there are 2 or more sequential order numbers, one or more of them will not be picked up by the report if most other fields are the same.
When I ran the report over a single 24 hour period, any orders that were missing from the month-long report would show up for that day.
This is the code I'm using for the query:
SELECT paydetail.ord_hdrnumber as ord_hdrnumber,
NULL As TotalRevenue,
paydetail.pyt_itemcode As Item,
NULL As ItemRevenue,
pyd_amount As ItemPay,
paydetail.asgn_type,
paydetail.asgn_id, ord_driver1,
ord_revtype1, pyt_description As ItemDesc,
pyt_basis As ItemBasis
FROM paydetail
LEFT OUTER JOIN payheader ON pyh_pyhnumber = pyh_number
JOIN orderheader on orderheader.ord_hdrnumber = paydetail.ord_hdrnumber
JOIN paytype on paytype.pyt_itemcode = paydetail.pyt_itemcode
WHERE ord_billto = #billto
AND ord_startdate BETWEEN #startdate + ' 00:00:00' AND #enddate + ' 23:59:59'
AND paydetail.pyt_itemcode NOT IN ('TCKEVE','TCKEXP','TCKDEB')
UNION ALL
SELECT invoicedetail.ord_hdrnumber as ord_hdrnumber,
ivh_totalcharge As TotalRevenue,
invoicedetail.cht_itemcode As Item,
ivd_charge As ItemRevenue,
NULL As ItemPay,
NULL As asgn_type,
NULL as asgn_id,
NULL as ord_driver1,
ord_revtype1,
[cht_description] As ItemDesc,
[cht_basis] As ItemBasis
FROM invoicedetail
LEFT OUTER JOIN invoiceheader ON invoiceheader.ivh_hdrnumber = invoicedetail.ivh_hdrnumber
JOIN orderheader on orderheader.ord_hdrnumber = invoicedetail.ord_hdrnumber
JOIN chargetype ON chargetype.cht_itemcode = invoicedetail.cht_itemcode
WHERE ivh_billto = #billto
AND ord_startdate BETWEEN #startdate + ' 00:00:00' AND #enddate + ' 23:59:59'
ORDER by ord_hdrnumber

Using results of JOIN statement to join on the results of another JOIN statement

I have the following 2 Join Statements:
--Get Total Hrs
DECLARE #BeginDate datetime, #EndDate datetime
set #BeginDate = '01-01-2013'
set #EndDate = '12-31-2013'
BEGIN
SELECT F.Type, E.Product, SUM(F.Hours * E.Amount) AS 'Total Hours'
FROM Hours H
INNER JOIN Equipment E
ON F.SN = E.SN
WHERE (F.Date BETWEEN #BeginDate AND #EndDate)
GROUP BY F.Type, E.Product
ORDER BY Product ASC
END
--Get Number of Unscheduled Removals
DECLARE #BeginDate1 datetime, #EndDate1 datetime
set #BeginDate1 = '01-01-2013'
set #EndDate1 = '12-31-2013'
BEGIN
SELECT LEFT(dbo.fn_GetPartName(R.PartID),CHARINDEX('-',dbo.fn_GetPartName(R.PartID), 1) - 1) AS 'Part No',
Count(s.status) AS NumberUnscheduledRemovals
FROM Repair R
INNER JOIN Conversion C
ON R.Performed = C.Performed
AND R.Confirmed = C.Confirmed
INNER JOIN Status S
ON C.StatusID = S.StatusID
WHERE (R.Received BETWEEN #BeginDate1 AND #EndDate1)
AND (S.Status = 'UNSCHEDULED')
GROUP BY LEFT(dbo.fn_GetPartName(R.PartID),CHARINDEX('-',dbo.fn_GetPartName(R.PartID), 1) - 1)
ORDER BY LEFT(dbo.fn_GetPartName(R.PartID),CHARINDEX('-',dbo.fn_GetPartName(R.PartID), 1) - 1) ASC
END
Both queries have results including part numbers (these have the same values). I want to INNER JOIN the results from both queries on the resulting part numbers. have been trying for a while but cant seem to get the syntax right to do it.
Use a temp table using CREATE TABLE #TempPartNum1 & #TempPartNum2.
Grab all the relevant data from the first two queries and put them in the temp tables, then join the temp tables.
You could also use a CTE ("Common Table Expression"):
;WITH QueryOne AS (
... put your first query here
), QueryTwo AS (
... put your second query here
) SELECT blah blah blah
FROM QueryOne INNER JOIN QueryTwo ON foo = bar
CTEs are very handy for things like this.

SQL add Sum to existing query (Cannot perform an aggregate function on an expression containing an aggregate or a subquery.)

I have a existing working SQL query I would like to now GroupBy but am getting the error: Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
Explanation of my scenario:
My main table (dbo.DataLog) contains 3 columns, TimestampUTC, MeterTagId, Data.
Data typically comes in at 15 minute intervals and I have many meters (MeterTagId) for each
TimestampUTC. The Data column is a float and this is a totalised value. i.e. to get the actual value for a meter period I need to subtract the last value from the current one. Before now I have successfully been querying individual meters but now I am trying to group by time and show a sum/total of all meters for that time.
Original working non summed query:
SELECT
l.TimestampUTC
-- Get this value minus the last value
,(SELECT (l.[Data] -
( SELECT TOP 1 l2.Data
FROM [DataLog] l2
WHERE l2.MeterTagId = l.MeterTagId
AND l2.TimestampUTC < l.TimestampUTC
ORDER BY l2.TimestampUTC DESC)
)
) AS Actual_Value
FROM [dbo].[DataLog] l
INNER JOIN [dbo].MeterTags t on t.MeterTagId = l.MeterTagId
INNER JOIN [dbo].Meters m on m.MeterId = t.MeterId
INNER JOIN [dbo].GroupsMeters gm on gm.MeterId = m.MeterId
INNER JOIN [dbo].Groups g on g.GroupId = gm.GroupId
LEFT OUTER JOIN dbo.Units u on u.UnitId = t.UnitId
WHERE (#MeterId is null OR M.MeterId in (#MeterId))
AND (#MeterTagId is null OR t.MeterTagId in (#MeterTagId))
AND (#StartDate is null OR l.TimestampUTC >= #StartDate)
AND (#EndDate is null OR l.TimestampUTC <= #EndDate)
AND (#GroupId is null OR g.GroupId in (#GroupId))
.
My attempt to to get the summary:
SELECT
l.TimestampUTC
-- Get this value minus the last value
, (SELECT SUM(l.[Data] -
( SELECT TOP 1 l2.Data
FROM [DataLog] l2
WHERE l2.MeterTagId = l.MeterTagId
AND l2.TimestampUTC < l.TimestampUTC
ORDER BY l2.TimestampUTC DESC)
)
)AS Actual_Value
FROM [dbo].[DataLog] l
INNER JOIN [dbo].MeterTags t on t.MeterTagId = l.MeterTagId
INNER JOIN [dbo].Meters m on m.MeterId = t.MeterId
INNER JOIN [dbo].GroupsMeters gm on gm.MeterId = m.MeterId
INNER JOIN [dbo].Groups g on g.GroupId = gm.GroupId
LEFT OUTER JOIN dbo.Units u on u.UnitId = t.UnitId
WHERE (#MeterId is null OR M.MeterId in (#MeterId))
AND (#MeterTagId is null OR t.MeterTagId in (#MeterTagId))
AND (#StartDate is null OR l.TimestampUTC >= #StartDate)
AND (#EndDate is null OR l.TimestampUTC <= #EndDate)
AND (#GroupId is null OR g.GroupId in (#GroupId))
AND t.Name ='Real Energy Net'
GROUP BY l.TimestampUTC
I have read other posts on here but can't get my head around the logic required, I imagine/hope this is something sql dev's come across regularly? Thanks!
OK, I worked it out, it's simple really. Hopefully this explanation helps someone else with the same issue in the future.
SELECT
myTable.TimestampUTC
, SUM(myTable.Actual_Value) as [Actual Value]
FROM
(
--My original query
) AS myTable
GROUP BY myTable.TimestampUTC

Adding zero values to report

Ok This is a good question I think.
At the moment I have a report showing amount of tickets per machine and how much each machine made in ticket sales.
Some machines sell Zero tickets but they are not includded in my report.
Now i want to include them.
there is a full list of all machines in machconfig table which I could compare to the ticketssold table which also has a field corresponding to the machine that sold it.
So I guess I could find all of the machines that havent sold any tickets by looking for machine id's (MCHterminalid) that dont appear in the ticketssold table (TKtermid column)
here is the code I've got so far..
SELECT TKtermID,
MCHlocation,
Count (TKvouchernum) AS Totaltickets,
Cast(Sum(TKcomission) AS FLOAT) / 100 AS Total_Comission
FROM ticketssold(NOLOCK)
INNER JOIN machconfig (NOLOCK)
ON MCHterminalID = TKtermID
WHERE cfglocationcountry = 'UK'
AND dateadded BETWEEN Getdate() - 100 AND Getdate()
GROUP BY vstermID,
cfglocation
ORDER BY Total_comission DESC
Change the inner join between ticketssold and machconfig to a right outer join to get all machines, regardless of a match in the tickets sold table. The count of TKVouchernum will return the zeros for you:
SELECT TKtermID,
MCHlocation,
Count (TKvouchernum) AS Totaltickets,
Cast(Sum(TKcomission) AS FLOAT) / 100 AS Total_Comission
FROM ticketssold(NOLOCK)
RIGHT OUTER JOIN machconfig (NOLOCK)
ON MCHterminalID = TKtermID
WHERE cfglocationcountry = 'UK'
AND dateadded BETWEEN DateAdd(DAY, -100, GetDate()) AND Getdate()
GROUP BY vstermID,
cfglocation
ORDER BY Total_comission DESC
OCD Version not totally proofed (also killing me that table names are not included before the fields). Use the outer join in combination with COALESCE
SELECT
TKTermID TicketTerminalId,
MchLocation MachineLocation,
COALESCE(COUNT(TKVoucherNum),0) TotalTickets,
COALESCE(CAST(SUM(TKComission) AS float),0) / 100 TotalComission
FROM
MachConfig (NOLOCK)
LEFT JOIN
TicketsSold (NOLOCK)
ON
TKtermID = MCHterminalID
WHERE
CfgLocationCountry = 'UK'
AND
DateAdded BETWEEN DATEADD(DAY, -100, GETDATE()) AND GETDATE()
GROUP BY
VSTermID,
CfgLocation
ORDER BY
COALESCE(CAST(SUM(TKComission) AS float),0) / 100 DESC; --Do this in reporting!
Do not use inner joins because they will eliminate rows. I start my joins with the table that has all the data. In this case machconfig and then do a left outer join to the table with the problematic data ticketssold.
You may also want to think about doing your grouping on the report side for flexibility.
Finally got it working the way I want.. Here is the proper code:
SELECT MCHTerminalID, MCHLocation, ISNULL(CONVERT(varchar(16), batch.LastBatchIn, 103),
'Did not batch in') AS LastBatchIn,
ISNULL(COUNT(Ticket.VoucherNum), 0) AS TotalVouchers,
ISNULL(SUM(Ticket.Sale), 0) AS TotalGrossAmount, ISNULL(SUM(Ticket.Refund),0) AS TotalRefundAmount, ISNULL(SUM(Ticket.Comission),0) AS TotalComission
FROM termConfig AS config WITH (NOLOCK)
LEFT OUTER JOIN
(SELECT bsTerminalID, MAX(bsDateTime) AS LastBatchIn
FROM batchSummary WITH (NOLOCK)
WHERE bsDateTime BETWEEN getdate()-50 AND getdate()
GROUP BY bsTerminalID
)
AS batch
ON config.MCHTerminalID = batch.bsTerminalID
LEFT OUTER JOIN
(SELECT DISTINCT TKTermID,
TKVoucherNum AS VoucherNum,
CAST(TKGrossTotal AS float)/100 AS Sale,
CAST(TKRefundAmount AS float)/100 AS Refund,
CAST(TKComission AS float)/100 AS Comission
FROM TicketVouchers WITH (NOLOCK)
WHERE dateAdded BETWEEN getdate()-50 AND getdate()
)
AS Ticket
ON
config.MCHTerminalID = Ticket.TKTermID
WHERE
config.MCHLocationCountry = 'uk'
AND config.MCHProductionTerminal = 'Y'
GROUP BY config.MCHTerminalID, config.MCHLocation, LastBatchIn
ORDER BY TotalComission desc
You could UNION the 'zero' rows to your original e.g.
<original query here>
...
UNION
SELECT MCHterminalID,
MCHlocation,
0 AS Totaltickets,
0 AS Total_Comission
FROM machconfig
WHERE NOT EXISTS (
SELECT *
FROM ticketssold
WHERE MCHterminalID = TKtermID
)
(Review for hints).