Generate Monthly based records in a period - sql

Here is my query to retreive the report for each month to get the paid and unpaid bookings
SELECT tbc.tbcId
,tbc.tbcName
,(
SELECT COUNT(bb.bbId)
FROM MyBooking bb
WHERE bb.tbcId = tbc.tbcId
AND bb.bbIsPayed = 1
AND Year(bb.bbDate) = '2016' --proc parameter #year
AND Month(bb.bbDate) = '7' --proc parameter #month
) AS PaidCount
,(
SELECT SUM(CASE
WHEN bb.bbVAT = 1
THEN (bb.bbPrice / 100) * 80
ELSE bb.bbPrice
END)
FROM MyBooking bb
WHERE bb.tbcId = tbc.tbcId
AND bb.bbIsPayed = 1
AND Year(bb.bbDate) = '2016' --proc parameter #year
AND Month(bb.bbDate) = '7' --proc parameter #month
) AS PaidAmount
,(
SELECT COUNT(bb.bbId)
FROM MyBooking bb
WHERE bb.tbcId = tbc.tbcId
AND bb.bbIsPayed <> 1
AND Year(bb.bbDate) = '2016' --proc parameter #year
AND Month(bb.bbDate) = '7' --proc parameter #month
) AS UnpaidCount
,(
SELECT SUM(CASE
WHEN bb.bbVAT = 1
THEN (bb.bbPrice / 100) * 80
ELSE bb.bbPrice
END)
FROM MyBooking bb
WHERE bb.tbcId = tbc.tbcId
AND bb.bbIsPayed <> 1
AND Year(bb.bbDate) = '2016' --proc parameter #year
AND Month(bb.bbDate) = '7' --proc parameter #month
) AS UnPaidAmount
FROM BookingCategories tbc
WHERE tbc.tbcIncludeReport = 1
AND tbc.tbcId IN (
SELECT DISTINCT con.tbcId
FROM CategoryXTags con
WHERE (
con.ttId = 26
OR con.ttId = 23
OR con.ttId = 24
)
)
ORDER BY tbc.tbcName ASC;
I have to run this for a given period of time, example Jan 2016 to Aug 2016.
As of now I run this in a loop by passing a #year and #month variable.
Is it possible to just pass #FromDate and #Todate and generate the report for each month in a same query? I couldnt able to think much in SQL to achieve this.

Untested, but I think will shrink your process down
Declare #Date1 Date = '2016-01-01'
Declare #Date2 Date = '2016-08-31'
Select Period = EOMonth(bb.bbDate)
,tbc.tbcId
,tbc.tbcName
,PaidCount = sum(case when bb.bbIsPayed=1 then 1 else 0 end)
,PaidAmount = sum(case when bb.bbIsPayed=1 and 1bb.bbVAT = 1 Then (bb.bbPrice / 100) * 80 ELSE bb.bbPrice end)
,UnpaidCount = sum(case when bb.bbIsPayed<>1 then 1 else 0 end)
,UnPaidAmount = sum(case when bb.bbIsPayed <> 1 and bb.bbVAT = 1 Then (bb.bbPrice / 100) * 80 ELSE bb.bbPrice end)
From BookingCategories tbc
Join MyBooking bb on (bb.bbId = tbc.tbcId)
Where tbc.tbcIncludeReport = 1
and tbc.tbcId IN (26,26,24)
and bb.bbDate between #Date1 and #Date2
Group By
EOMonth(bb.bbDate)
,tbc.tbcId
,tbc.tbcName
Order By 1,tbc.tbcName ASC

Related

Combine multiple queries in 1 return row

I have a query which should return 1 row for each DetectorID. What we currently have is the following:
DECLARE #StartDate datetime SET #StartDate = '2017-12-01 00:00'
DECLARE #EndDate datetime select #EndDate ='2018-01-01 00:00'
DECLARE #Limit1 real SET #Limit1 = 200; DECLARE #AssenLimit1 real SET #AssenLimit1 = 0;
DECLARE #Limit2 real SET #Limit2 = 300; DECLARE #AssenLimit2 real SET #AssenLimit2 = 0;
DECLARE #Limit3 real SET #Limit3 = 350; DECLARE #AssenLimit3 real SET #AssenLimit3 = 0;
DECLARE #Limit4 real SET #Limit4 = 400; DECLARE #AssenLimit4 real SET #AssenLimit4 = 0;
DECLARE #Limit5 real set #Limit5 = 500; DECLARE #AssenLimit5 real SET #AssenLimit5 = 0;
SELECT DetectorID, AVG(ValidWIM) AS 'PI_mean_WIM',
COUNT(ValidWIM) AS 'PI_mean_WIM2',
COUNT(CASE
WHEN ValidWIM > 0.5 THEN ValidWIM ELSE NULL END)
AS 'PI_mean_WIM3'
,AVG((ValidWDD_Left+ValidWDD_Right)/2) AS 'PI_mean_WDD'
,COUNT(ValidWDD_Left) AS 'PI_mean_WDD2'
,COUNT (CASE
WHEN (ValidWDD_Left>0.5 AND ValidWDD_Right>0.5) THEN ValidWDD_Left ELSE NULL END)
AS PI_mean_WDD3
,COUNT(CASE
WHEN AxleLoad IS NOT NULL Then TrainPassageInformationID ELSE NULL END)
AS 'nWheels'
, COUNT(CASE
WHEN (PeakForceLeft > #Limit1 OR PeakForceRight>#Limit1) THEN TrainPassageInformationID ELSE NULL END)
AS 'n>200'
, COUNT(CASE
WHEN (PeakForceLeft > #Limit2 OR PeakForceRight>#Limit2) THEN TrainPassageInformationID ELSE NULL END)
AS 'n>300'
, COUNT(CASE
WHEN (PeakForceLeft > #Limit3 OR PeakForceRight>#Limit3) THEN TrainPassageInformationID ELSE NULL END)
AS 'n>350'
, COUNT(CASE
WHEN (PeakForceLeft > #Limit4 OR PeakForceRight>#Limit4) THEN TrainPassageInformationID ELSE NULL END)
AS 'n>400'
, COUNT(CASE
WHEN (PeakForceLeft > #Limit5 OR PeakForceRight>#Limit5) THEN TrainPassageInformationID ELSE NULL END)
AS 'n>500'
From WheelDamage
where (TimeOfAxle > #StartDate AND TimeOfAxle < #EndDate) and DetectorID in (11,12)
GROUP BY DetectorID
order by DetectorID asc
SELECT DetectorID,
AVG(PeakForceLeft) AS 'NoiseLeft' FROM WheelDamage as t
where PeakForceLeft in (
select top 10 percent PeakForceLeft
from wheeldamage as tt
where tt.WheelDamageID = t.WheelDamageID AND tt.PeakForceLeft <> 0 AND tt.PeakForceLeft IS NOT NULL AND (t.TimeOfAxle > #StartDate AND t.TimeOfAxle < #EndDate)
order by tt.PeakForceLeft asc)
Group By DetectorID
order by DetectorID asc
SELECT DetectorID,
AVG(PeakForceRight) AS 'NoiseRight' FROM WheelDamage as t
where PeakForceLeft in (
select top 10 percent PeakForceRight
from wheeldamage as tt
where tt.WheelDamageID = t.WheelDamageID AND tt.PeakForceRight <> 0 AND tt.PeakForceLeft IS NOT NULL AND (t.TimeOfAxle > #StartDate AND t.TimeOfAxle < #EndDate)
order by tt.PeakForceLeft asc)
Group By DetectorID
order by DetectorID asc
SELECT DetectorId, COUNT (DateTime) AS 'Tags1'
FROM [TagPassage]
WHERE Valid = 1 AND (DateTime > #StartDate AND DateTime < #EndDate)
GROUP by DetectorID
Order by DetectorID asc
SELECT DetectorID, COUNT(CASE
WHEN (TotalWeight=0 OR TotalWeight IS NULL) AND (HasTrainStandStill<>1 OR HasTrainStandStill IS NULL) THEN (TrainPassageInformationID) ELSE NULL END) AS 'notAnalyzed'
, SUM (TotalWeight) AS 'TotalWeight'
FROM TrainPassageInformation
WHERE (Datetime > #StartDate AND Datetime < #EndDate)
Group By DetectorID
order by DetectorID asc
This is returing 5 new rows which I understand. This is because i have 5 select statements. However, I need to know how i can put the bottom 4 select statements in the top one so that it will only return 1 row.
I have tried with Select(Select X xxx). But that gave the error that it is returning more then 1 rows.
The image above is showing the current result. I want the bottom 4 tables to be columns in the first table.
can you just join/left join all the scripts together as table and link by DetectorID, then u can select the columns from the 4 scripts at the bottom to the right.

Conditional Where when using Group By

I have a working procedure to show the report for given range of period.
The below proc finds all the bookings for the given period of time and shows for each month group
CREATE PROCEDURE [dbo].[GetSummaryOverviewReport] (
#StartDate SMALLDATETIME = NULL
,#EndDate SMALLDATETIME = NULL
,#IncludeVAT BIT = 0
,#AddedAfter SMALLDATETIME
,#HasObservation BIT = 0
,#IncludeCancelledBooking BIT = 0
)
AS
BEGIN
SET NOCOUNT ON
BEGIN
SELECT YEAR(StartTime) [Year]
,MONTH(StartTime) [Month]
,COUNT(BookingId) [BookingCount]
,SUM(CASE
WHEN IsVAT = 1
AND #IncludeVAT = 1
THEN (Price / 100) * 80
ELSE Price
END) AS TotalPrice
,PaidCount = sum(CASE
WHEN B.PaymentStatus = 'FullyPaid'
THEN 1
ELSE 0
END)
,PaidSum = sum(CASE
WHEN B.PaymentStatus = 'FullyPaid'
THEN (
CASE
WHEN IsVAT = 1
AND #IncludeVAT = 1
THEN (Price / 100) * 80
ELSE Price
END
)
ELSE 0
END)
,C.CategoryId
,CategoryName
FROM Category c
LEFT JOIN Booking B ON C.CategoryId = B.CategoryId
WHERE B.AddedDateTime > #AddedAfter
AND ISNULL(B.IsCancelled, 0) = 0
AND (
(
B.StartTime BETWEEN #StartDate
AND #EndDate
)
OR (
B.StartTime BETWEEN #StartDate
AND #EndDate
)
)
AND (
#HasObservation = 0
OR B.PatientID IN (
SELECT PatientID
FROM PatientXObservation O
WHERE ObservationId IN (
1
,2
,4
)
)
)
GROUP BY YEAR(StartTime)
,MONTH(StartTime)
,C.CategoryId
,CategoryName
ORDER BY 1
,2
,CategoryName
END
END
Now we want to add a filter #IncludeCancelledBooking parameter. So user can select whether to show cancelled bookings or not. As of now the procedure ignores the cancelled booking and shows only non cancelled booking..
I couldn't able to find out how to add this condition while grouping the records. I need to use AND ISNULL(B.IsCancelled, 0) = 0 based on #IncludeCancelledBooking
Is this the logic that you want?
(#IncludeCancelled <> 'Y' OR Booking ISNULL(B.IsCancelled, 0) = 0)
If IsCancelled is also a BIT(like #IncludeCancelled), then you could use:
AND ISNULL(B.IsCancelled, 0) IN (0, #IncludeCancelled)
If #IncludeCancelled is 0, then this is effectively the same logic you have now (i.e. = 0). If #IncludeCancelled is 1, then this includes where IsCancelled = 1.
Assuming you are passing value 1 for the variable #IncludeCancelled for including the cancelled booking. Then change the WHERE condition like below.
AND ISNULL(B.IsCancelled,0)=
CASE WHEN #IncludeCancelled=1
THEN ISNULL(B.IsCancelled,0)
ELSE 0 END

How to execute the query only when mainframe is up?

I have a query which has to be executed only when the mainframe is up. Mainframe is down during these hours
tuesday to saturday - 1am to 6am,
sunday - 1am - 12pm.
I am trying to declare a variable which gets the current date and time and then trying to write a logic in the if statement to satisfy the above condition.
if #new_que_stat_cd = 'U'
BEGIN
--declare #recv_time datetime = getdate()
--if CASE WHEN datepart(dw,#recv_time) in ('SUNDAY') AND
--,'TUESDAY','WEDNESDAY','
--declare #ident int = IDENT_CURRENT( 'SADEV.RO_Transcript.ETQueueCtrl' )
UPDATE NEW SET [ETQueueCtrlStatusCd] = 'U'
from sadev.RO_Transcript.ETQueueCtrl NEW
where new.[ETQueueCtrlStatusCd] = 'S'
AND new.ErrorFl = 'N'
and new.VendorTransactionID is not null
and new.VendorTransactionIDRcvdDate is not null
and new.ETQueueCtrlID = #queuectrl_id
select new.VendorTransactionIDRcvdDate
from sadev.RO_Transcript.ETQueueCtrl NEW
where new.[ETQueueCtrlStatusCd] = #new_que_stat_cd
AND new.ErrorFl = 'N'
and new.VendorTransactionID is not null
and new.ETQueueCtrlID = #queuectrl_id
END
WILL THIS LOGIC WORK FOR THE ABOVE CONDITION
declare #recv_time datetime = getdate()
if (convert(varchar,(datepart(DAY,#recv_time))) in ('SUNDAY')
AND convert(varchar, #recv_time, 114) between convert(datetime,'01:00') and convert(datetime,'12:00'))
or
convert(varchar,(datepart(DAY,#recv_time))) in ('Tuesday','Wednesday','Thursday','Friday','Saturday')
AND convert(varchar, #recv_time, 114) between convert(datetime,'01:00') and convert(datetime,'06:00')
Based on: DATEPART (Transact-SQL)
Try this:
IF #new_que_stat_cd = 'U'
BEGIN
DECLARE #currDate DATETIME=GETDATE();
DECLARE #runProcess BIT=0;
SELECT #runProcess=CASE
WHEN DATEPART(dw, #currDate) IN
(3, 4, 5, 6, 7
)
THEN CASE
WHEN DATEPART(hh, #currDate) BETWEEN 1 AND 6
THEN 1
ELSE 0
END
WHEN DATEPART(dw, #currDate) IN
(1
)
THEN CASE
WHEN DATEPART(hh, #currDate) BETWEEN 1 AND 12
THEN 1
ELSE 0
END
ELSE 0
END;
IF #runProcess = 1
BEGIN
UPDATE NEW
SET ETQueueCtrlStatusCd='U'
FROM sadev.RO_Transcript.ETQueueCtrl NEW
WHERE new.ETQueueCtrlStatusCd = 'S'
AND new.ErrorFl = 'N'
AND new.VendorTransactionID IS NOT NULL
AND new.VendorTransactionIDRcvdDate IS NOT NULL
AND new.ETQueueCtrlID = #queuectrl_id;
SELECT new.VendorTransactionIDRcvdDate
FROM sadev.RO_Transcript.ETQueueCtrl NEW
WHERE new.ETQueueCtrlStatusCd = #new_que_stat_cd
AND new.ErrorFl = 'N'
AND new.VendorTransactionID IS NOT NULL
AND new.ETQueueCtrlID = #queuectrl_id;
END;
END;
Where 3,4,5,6,7 are Tuesday to Saturday respectively and 1 is Sunday.

Update multiple variables in a single query

I have a table with Sum of Amounts for Each Weekday (Sunday to Saturday) . Table structure is as below.
I need to assign these table values into parameters. For E.g : I need to assign sum of rdate '2015-11-15' i.e 324 to a variable #sundayval , 374 to variable #mondayval etc...
How to do this In a single update query. I have tried out with Case statement,
But it only assigns value to variable #saturdayval .
Thanks for the Help.
This does the job. It doesn't depend on any particulat DATEFIRST settings - it instead uses an arbitrarily chosen sunday (I picked 17th May this year) (what I usually refer to as a "known good" date because it has the property we're looking for, in this case the right day of the week):
declare #t table ([sum] int not null,rdate datetime2 not null)
insert into #t([sum],rdate) values
(324,'20151115'),
(374,'20151116'),
(424,'20151117'),
(474,'20151118'),
(524,'20151119'),
(574,'20151120'),
(624,'20151121')
declare #sundayval int
declare #mondayval int
declare #tuesdayval int
declare #wednesdayval int
declare #thursdayval int
declare #fridayval int
declare #saturdayval int
select
#sundayval = SUM(CASE WHEN DATEPART(weekday,rdate) = DATEPART(weekday,'20150517') THEN [sum] END),
#mondayval = SUM(CASE WHEN DATEPART(weekday,rdate) = DATEPART(weekday,'20150518') THEN [sum] END),
#tuesdayval = SUM(CASE WHEN DATEPART(weekday,rdate) = DATEPART(weekday,'20150519') THEN [sum] END),
#wednesdayval = SUM(CASE WHEN DATEPART(weekday,rdate) = DATEPART(weekday,'20150520') THEN [sum] END),
#thursdayval = SUM(CASE WHEN DATEPART(weekday,rdate) = DATEPART(weekday,'20150521') THEN [sum] END),
#fridayval = SUM(CASE WHEN DATEPART(weekday,rdate) = DATEPART(weekday,'20150522') THEN [sum] END),
#saturdayval = SUM(CASE WHEN DATEPART(weekday,rdate) = DATEPART(weekday,'20150523') THEN [sum] END)
from #t
select #sundayval,#mondayval,#tuesdayval,#wednesdayval,#thursdayval,#fridayval,#saturdayval
Result:
----------- ----------- ----------- ----------- ----------- ----------- -----------
324 374 424 474 524 574 624
Ok - let's do it this way: the else case is set to return itself, so each variable essentially aggregates as a coalesce. Note: I don't have any way to test this right now. :)
SELECT
#sundayval = case when DATEPART(weekday, rdate) = 1 then sum else #sundayval end
, #mondayval = case when DATEPART(weekday, rdate) = 2 then sum else #mondayval end
, #tuesdayval = case when DATEPART(weekday, rdate) = 3 then sum else #tuesdayval end
, #wednesdayval = case when DATEPART(weekday, rdate) = 4 then sum else #wednesdayval end
, #thursdayval = case when DATEPART(weekday, rdate) = 5 then sum else #thursdayval end
, #fridayval = case when DATEPART(weekday, rdate) = 6 then sum else #fridayval end
, #saturdayval = case when DATEPART(weekday, rdate) = 7 then sum else #saturdayval end
FROM TABLE
I have No idea Whether a Single UPDATE Statement will do this. I have assigned value for Each Variable like as Below,
SELECT #SunTotal = [sum]
FROM [table]
where rdate = #Startdate
SELECT #MonTotal = [sum]
FROM [table]
where rdate = DATEADD(DAY,1,#Startdate)
SO ON...

Calculating monthly sales based on a quarter

I need to calculate the monthly sales for a given quarter.
Here is my code to calculate the previous quarter.
set #quarter = datepart(QQ, getdate()) - 1
if #quarter = 0
begin
set #quarter = 4
set #year = datepart(year, getdate()) -1
end
else set #year = datepart(year, getdate())
Here is my code to calculate the average monthly sales for the entire quarter.
SELECT TOP 5 d.sdealer_name, COUNT(c.icontract_id) / 3 as 'AverageMonthlySales'
FROM dealers d
INNER JOIN contracts c
ON c.sdealer_number = d.sdealer_number
WHERE (d.sdealer_number NOT LIKE '%demo%'
AND d.sdealer_status in ('A', 'R')
AND c.sagent_number = #sagent_number
AND c.sstatus in ('P', 'A', 'C', 'E')
AND c.iproduct_type_id in (4)
AND DATEPART(QQ, c.dtcontract_sale_date) = #quarter
AND DATEPART(year, c.dtcontract_sale_date) = #year)
GROUP BY d.sdealer_name
ORDER BY COUNT(distinct c.icontract_id) desc
How would I calculate the total sales for each month dynamically for the given quarter?
ctrl+h ... just replace quarter datepart with month. is there some reason you haven't tried that?
set #month = datepart(month, getdate()) - 1
if #month = 0
begin
set #month = 12
set #year = datepart(year, getdate()) -1
end
else set #year = datepart(year, getdate())
SELECT TOP 5 d.sdealer_name, COUNT(c.icontract_id) as 'AverageMonthlySales'
FROM dealers d
INNER JOIN contracts c
ON c.sdealer_number = d.sdealer_number
WHERE (d.sdealer_number NOT LIKE '%demo%'
AND d.sdealer_status in ('A', 'R')
AND c.sagent_number = #sagent_number
AND c.sstatus in ('P', 'A', 'C', 'E')
AND c.iproduct_type_id in (4)
AND DATEPART(month, c.dtcontract_sale_date) = #month
AND DATEPART(year, c.dtcontract_sale_date) = #year)
GROUP BY d.sdealer_name
ORDER BY COUNT(distinct c.icontract_id) desc