I have two table,as per requirement we need to subtract the values as given below. kindly assist me how to solve this puzzle....
Table1
MONTH Fee(Advance)
APRIL 5000
Table2
MONTH Fee
MAY 2000
JUNE 300
JULY 1800
AUG 1200
Sep 1500
Expecting Result
ROW 1 MAY 5000(TABLE1.ADVANCE)-2000(TABLE2.FEE)= 3000
ROW 2 JUNE 3000-300 = 2700
ROW 3 JULY 2700-1800 = 900
ROW 4 AUG 900-1200 = -300
ROW 5 Sep -300-1500 = -1800
I am not sure if this is the right way of doing this. Instead of SQL statement, maybe stored procedure will help?
DECLARE #AdvanceFee INT;
DECLARE #cnt INT = 1;
DECLARE #cnt_total INT = (Select Count(MONTH) From Table2);
SET #AdvanceFee = (Select Fee(Advance) from Table1)
WHILE #cnt <= #cnt_total
BEGIN
Select MONTH, #AdvanceFee = #AdvanceFee - Fee
FROM Table2
WHERE ROW_NUMBER = #cnt
SET #cnt = #cnt + 1;
END
You need a table containing month names and numbers ('MAY' = 5, 'Sep' = 9, ...). Then use SUM OVER to get a running total:
select
t.month,
(select fee from table1 where month = 'APRIL') - sum(t.fee) over (order by m.monthnum)
as balance
from table2 t
join months m on m.name = t.month
order by m.monthnum;
Related
In one table I have currency rate in some time period(five years). In another table, I have calculated data.
I have the task. I need to get statistics by every week summary from joined tables
I am having this at the moment:
DECLARE #Category_RentHouse INT = 3;
DECLARE #Category_Parents INT = 5;
DECLARE #Category_Salary INT = 9;
DECLARE #TestDateStart DATE = '2012-01-01';
DECLARE #TestDateFinish DATE = '2012-01-07';
select Weeks, SUM(Cash_Usd) TotalMoney
from (select CAST(RateDate AS DATE) Weeks,
CASE WHEN CategoryID = #Category_RentHouse THEN (TransactionAmount*(-1))
WHEN CategoryID = #Category_Parents THEN TransactionAmount
WHEN CategoryID = #Category_Salary THEN CAST((TransactionAmount /
RateValue) AS MONEY)
ELSE CAST((TransactionAmount*(-1) / RateValue) AS MONEY)
END AS Cash_Usd
FROM (select * from Marathon.dbo.Transactions T
LEFT JOIN IntermediateM.dbo.Rates R ON T.TransactionDate = R.RateDate) Y
) RR
WHERE Weeks BETWEEN #TestDateStart AND #TestDateFinish
GROUP BY DATEPART(week, Weeks), Weeks
ORDER BY Weeks
And result of run this small code is
But it would better if in fields Weeks and TotalSumm I will get the next:
Weeks TotalSumm
2012-01-07 -552...
2012-01-14 ....
I think you just need to fix the select and group by:
SELECT MIN(Dte) as Weeks, SUM(Cash_Usd) TotalMoney
FROM (SELECT CAST(RateDate AS DATE) as Dte,
(CASE WHEN CategoryID = #Category_RentHouse THEN (TransactionAmount*(-1))
WHEN CategoryID = #Category_Parents THEN TransactionAmount
WHEN CategoryID = #Category_Salary THEN CAST((TransactionAmount / RateValue) AS MONEY)
ELSE CAST((TransactionAmount*(-1) / RateValue) AS MONEY)
END) AS Cash_Usd
FROM Marathon.dbo.Transactions T LEFT JOIN
IntermediateM.dbo.Rates R
ON T.TransactionDate = R.RateDate
WHERE Weeks BETWEEN #TestDateStart AND #TestDateFinish
) RT
GROUP BY DATEPART(week, Weeks)
ORDER BY Weeks
I have the following table for example. I would like to calculate the changes increase or decrease from previous month. This will show a percentage of change from previous month.
Location Month Sales
A Jan 1753
B Jan 32130
C Jan 71353
D Jan 74885
E Jan 50241
F Jan 66393
A Feb 80633
B Feb 67918
C Feb 73330
D Feb 33269
E Feb 78915
F Feb 98817
A Mar 80633
B Mar 67918
C Mar 73330
D Mar 33269
E Mar 78915
F Mar 98817
I wan to create a table like following. I searched stack overflow but was not able to get table.
Location Selected Current_Month Prvisous_Month Change
A Feb 80633 1753 4500%
B Feb 67918 32130 111%
C Feb 73330 71353 3%
D Feb 33269 74885 -56%
E Feb 78915 50241 57%
F Feb 98817 66393 49%
If you can't change the datatype of the "Month" column, for whatever reason, then this solution may work
DECLARE #Table TABLE ([Location] CHAR(1), [Month] NVARCHAR(3), Sales INT )
INSERT INTO #Table
([Location], [Month], Sales)
VALUES
('A',N'Jan',1753),
('B',N'Jan',32130),
('C',N'Jan',71353),
('D',N'Jan',74885),
('E',N'Jan',50241),
('F',N'Jan',66393),
('A',N'Feb',80633),
('B',N'Feb',67918),
('C',N'Feb',73330),
('D',N'Feb',33269),
('E',N'Feb',78915),
('F',N'Feb',98817),
('A',N'Mar',80633),
('B',N'Mar',67918),
('C',N'Mar',73330),
('D',N'Mar',33269),
('E',N'Mar',78915),
('F',N'Mar',98817)
DECLARE #Selection NVARCHAR(3) = N'Feb' -- Enter Selected Month here
;WITH cteX
AS(
SELECT
T.[Location]
, T.[Month]
, MonthNum = MONTH([T].[Month] + ' 1 1900') --Use some dummy date here
, T.Sales
FROM #Table T
)
SELECT
T.[Location]
, Selected = T.Month
, CurrentMonth = T.Sales
, PreviousMonth = T1.Sales
, Change = CAST((T.Sales - T1.Sales) / (T1.Sales * 1.0) * 100.0 AS DECIMAL)
FROM cteX T
INNER JOIN
cteX T1 ON T1.MonthNum = T.MonthNum - 1
AND T1.[Location] = T.[Location]
WHERE
T.[Month] = #Selection
Output
Something like this should be a good start. As Cool_Br33ze noted, you should rethink the date column of this table.
SELECT
*,
referenceTimePeriod / NULLIF(comparisonTimePeriod, 0) -- avoid DIV0 errors
FROM (
SELECT Location, Sales
FROM myTable
WHERE month = 'jan'
) AS referenceTimePeriod
FULL JOIN(
SELECT Location, Sales
FROM myTable
WHERE month = 'feb'
) AS comparisonTimePeriod ON referenceTimePeriod.Location = comparisonTimePeriod .Location
SELECT A.Location, 'Feb' AS Selected, A.Sales AS Current_Month
, B.Sales AS Prvisous_Month, (A.Sales - B.Sales)/ B.Sales AS Change
FROM YourTable A JOIN YourTable B
ON A.Month = B.Month + 1 -- You will have to represent Months by numbers
WHERE A.Month = 2 -- Selected month
Assuming that you change the Month attribute to date then you can use a LAG window function easily like this
SELECT location,
month,
sales,
lag(sales) over (order by month) previous,
(sales/lag(sales) over (order by month) - 1) * 100 as change
FROM your_table
WHERE month = 'feb'
The major issue now in your task is the correct ordering of Month which would be much more easier with date, or numbers.
EDIT: You can use the ordering solution of Cool_Br33ze for current data:
SELECT location,
month,
sales,
lag(sales) over (order by MONTH([T].[Month] + ' 1 1900')) previous, -- taken from Cool_Br33ze solution
(sales/lag(sales) over (order by MONTH([T].[Month] + ' 1 1900')) - 1) * 100 as change
FROM your_table
WHERE month = 'feb'
However, the best option is to change the data type of Month ...
Having difficulty getting my head around this one.
I've been asked to create a report showing customers who signed up in the same month in previous year.
Invoice table looks a bit like this: (can't figure out how to create a nicer table)
invoiceid customerid monthinvoice yearinvoice
1 50 July 2016*
2 51 July 2016
3 52 July 2016*
4 53 July 2016
5 54 August 2016
6 50 July 2017*
7 51 August 2017
8 52 July 2017*
9 53 August 2017
10 54 September 2017
The only proper date column used is date the invoice was generated and the date payment received.
The records marked with * are the ones I'm only interested in, I just want to see 2 records returned when I pass a month as a parameter (I'll be asked to show how many customers have renewed in August for example. If the 1st invoice was in July 2016 and next invoice in August 2017 they will be treated as a new customer, not a renewal (must be exactly 12 months))
1) 50
2) 52
Any help much appreciated.
Here is one way. First we get all invoices for this month, current year, then union to the same month of the previous year. Then, we filter on customers who have a record for both using HAVING.
;with cte as(
select *
from yourtable
where
(monthinvoice = #monthinvoice
and yearinvoice = datepart(year,getdate()))
union
select *
from yourtable
where
(monthinvoice = #monthinvoice
and yearinvoice = datepart(year,dateadd(year,-1,getdate()))))
select *
from cte
where customerid in (select customerid from cte group by customerid having count(invoiceid) > 1)
I think this should do the trick for you-
SELECT I1.invoiceid, I1.customerid, I1.monthinvoice, I1.yearinvoice, I2.yearinvoice
FROM Invoice_table I1
INNER JOIN Invoice table I2
ON I1.customerid = I2.customerid
AND I1.monthinvoice = I2.monthinvoice
AND I1.yearinvoice = I2.yearinvoice + 1
something like this
select customerid , monthinvoice from yourtable
where yearinvoice in (2016, 2017) and monthinvoice = 'July'
group by customerid , monthinvoice
having count(*) = 2
Something like the following should give you some ideas as to how to build the report out.
Declare #ReportYear as int = 2017;
--this should show all customers with invioices for these months in both 2017 and 2016
select a.customerid, a.monthinvoice
from
(
--get people with invoice last year
Select distinct customerid, monthinvoice
from Invoices i0
where yearinvoice = #ReportYear - 1
) a
join
(
--get people with invoice this year
Select distinct customerid, monthinvoice
from Invoices i0
where yearinvoice = #ReportYear
) b on a.customerid = b.customerid
and a.monthinvoice = b.monthinvoice
If Im following your question correctly...
SELECT customerid FROM InvTblName T
INNER JOIN (SELECT customerID
FROM InvTblName
HAVING Z.invyear=T.invyear+1) Z
ON T.invmonth=Z.invmonth
I'm using SQL Server 2008 R2.
I’m querying a table of Hospital Appointment Slots and trying to return a list of how many appointment slots for a specific doctor are flagged as being booked, grouped by week number/year.
There are some instances of weeks that don’t have any booked appointments yet, but I want the result to list ALL the forthcoming weeks, even where the count of booked appointment slots is zero.
The output I’m looking for is along these lines:
-------------------------------------------
Year | Week Number | Number of Booked Slots
-------------------------------------------
2017 | 48 | 10
2017 | 49 | 0
2017 | 50 | 4
2017 | 51 | 2
2017 | 52 | 0
2018 | 1 | 5
I understand that a standard select aggregating the results won’t show those weeks where there's a zero count of records, because there’s nothing to return – so I’ve tried to get around this by using a cte to first produce a list of all the forthcoming weeks.
However, try as I might, I can’t get the query to display the zero weeks...
I’ve seen a number of solutions to similar problems to this, but despite experimenting I haven’t been able to apply them to my particular problem (including SQL Count to include zero values)
This is the latest iteration of the query I’ve written so far.
WITH CTE_Dates AS
(
SELECT DISTINCT Slot_Start_Date AS cte_date
FROM [Outpatients.vw_OP_Clinic_Slots WITH (NOLOCK)
)
SELECT
DATEPART(year,OPCS.Slot_Start_Date) [Year]
,DATEPART(week,OPCS.Slot_Start_Date) [Week Number]
,count(OPCS.Slot_Start_Date) [Number of Booked Slots]
FROM
Outpatients.vw_OP_Clinic_Slots OPCS WITH (NOLOCK)
LEFT OUTER JOIN CTE_Dates ON OPCS.Slot_Start_Date=CTE_Dates.cte_date
LEFT OUTER JOIN Outpatients.vw_OP_Clinics CLIN ON OPCS.Clinic_Code=CLIN.Clinic_Code
WHERE
OPCS.Slot_Start_Date >= '14/08/2017'
AND OPCS.Booked_Flag = 'Y'
AND CLIN.Lead_Healthcare_Professional_Name = 'Dr X'
GROUP BY
DATEPART(year,OPCS.Slot_Start_Date)
,DATEPART(week,OPCS.Slot_Start_Date)
ORDER BY
DATEPART(year,OPCS.Slot_Start_Date)asc
,DATEPART(week,OPCS.Slot_Start_Date)asc
The result it’s returning me is correct, BUT I just need it to include those weeks in the list where the count is zero.
Please can anyone explain where I’m going wrong? I’m guessing I’m not joining the cte correctly, but I’ve tried both right and left joins which produce the same result. I’ve also tried inverting the query by swopping the above query statement and cte around, but this doesn’t work either.
Appreciate any guidance anyone can suggest.
Just RIGHT JOIN #ListOfWeeks table to the result set you have:
DECLARE #ListOfWeeks TABLE ([Week_No] int, [Year_Number] int);
DECLARE #i tinyint = 1, #y int = 2010;
WHILE #i <= 52 AND #y < 2018
BEGIN
INSERT INTO #ListOfWeeks([Week_No], [Year_Number]) VALUES (#i, #y);
IF #i = 52 BEGIN
SET #i = 0
SET #y +=1
END
SET #i += 1
END
SELECT * FROM #ListOfWeeks
WITH [Your_Part] AS(
SELECT
DATEPART(year,OPCS.Slot_Start_Date) [Year]
,DATEPART(week,OPCS.Slot_Start_Date) [Week Number]
,count(OPCS.Slot_Start_Date) [Number of Booked Slots]
FROM
Outpatients.vw_OP_Clinic_Slots OPCS WITH (NOLOCK)
LEFT OUTER JOIN CTE_Dates ON OPCS.Slot_Start_Date=CTE_Dates.cte_date
LEFT OUTER JOIN Outpatients.vw_OP_Clinics CLIN ON OPCS.Clinic_Code=CLIN.Clinic_Code
WHERE
OPCS.Slot_Start_Date >= '14/08/2017'
AND OPCS.Booked_Flag = 'Y'
AND CLIN.Lead_Healthcare_Professional_Name = 'Dr X'
GROUP BY
DATEPART(year,OPCS.Slot_Start_Date)
,DATEPART(week,OPCS.Slot_Start_Date)
),
SELECT xxx.[Year_Number], xxx.[Week_No], yp.[Number of Booked Slots]
FROM [Your_Part] yp
RIGHT JOIN #ListOfWeeks xxx ON yp.[Year] = xxx.[Year_Number] AND yp.[Week Number] = xxx.[Week_No]
IF OBJECT_ID(N'tempdb..##cal_weeks_temp', N'U') IS NOT NULL
DROP TABLE ##cal_weeks_temp;
create table ##cal_weeks_temp (date_of_week date, week_num int)
declare #start_date date
declare #end_date date
set #start_date='01/01/2017'
set #end_date='12/31/2018'
while #start_date<#end_date
begin
set #start_date=dateadd(day,1,#start_date)
insert into ##cal_weeks_temp values (#start_date,DATEPART(week,#start_date))
end
select YEAR(t1.date_of_week) 'YEAR',t1.week_num,
sum(case convert(varchar,t2.BookedTime,105) when convert(varchar,t1.date_of_week,105) then 1 else 0 end) 'count'
from ##cal_weeks_temp t1
left join Your_Table t2
on convert(varchar,t2.BookedTime,105)=convert(varchar,t1.date_of_week,105)
group by YEAR(t1.date_of_week) ,t1.week_num
order by YEAR(t1.date_of_week) ,t1.week_num
I have a table that looks like this:
Within the query I need to find the Maximum Import value that occurs over two time periods (rows) where the value is greater that a defined Threshold and apply a rate. If it happens over more than two time periods a different rate will be used
Threshold = 1000
Rate 1 (2 consecutive) = 100
Rate 2 (> 2 consecutive) = 200
Id DateTime Import Export Total
1 2016-01-13 00:00 1000 500 1500
2 2016-01-13 00:15 2500 100 3000
3 2016-01-13 00:30 1900 200 2100
4 2016-01-13 01:00 900 100 1200
Ids 2 and 3 are > Threshold so the query should return the MIN value of those (2500,1900) = 1900 minus the Threshold (1000) = 900. Apply the rate Rate1 * 900 = 9000
If we change the value of Id 4 to 1200 then the MIN value would be 1200. Less the threshold = 200. 200 * Rate2 = 4000
Any help would be greatly appreciated!
Update after feedback. My challenge appears to be that I'm not grabbing the 2nd highest value. Here is an example of the dataset:
Dataset example
I added another var to shrink the list down to test gap and island portion. Here is a smaller subset:
Subset
Here is the code:
WITH CTE AS (
SELECT LogTable.[LocalTimestamp] as thetime,LogTable.[SystemImport] as import, LogTable.[Id] - ROW_NUMBER() OVER (ORDER BY LogTable.[Id]) AS grp
FROM {System_KWLogRaw} LogTable
WHERE LogTable.[SystemImport] between #DemandThreshold and #In1 and
DATEPART(year,#inDate) = DATEPART(year, LogTable.[LocalTimestamp]) and
DATEPART(month,#inDate) = DATEPART(month, LogTable.[LocalTimestamp]) and
DATEPART(day,#inDate) = DATEPART(day, LogTable.[LocalTimestamp])
),
counted AS (
SELECT *, COUNT(*) OVER (PARTITION BY grp) AS cnt
FROM CTE
)
SELECT MAX(counted.import) as again1
FROM counted
WHERE cnt > 3 and counted.import < (SELECT MAX(counted.import) FROM counted)
This returns 3555.53 instead of 3543.2 which is the 2nd highest value
This will do what you're asking for:
with x as (
select
t1.Id,
t1.DateTime,
t1.Import,
t1.Export,
t1.Total,
count(t2.Import) over (partition by 1) as [QualifyingImports],
min(t2.Import) over (partition by 1) as [MinQualifyingImport]
from
myTable t1
left join myTable t2 on t2.Import > 1000 and t2.Id = t1.Id
where
t1.DateTime >= '2016-01-13'
and t1.DateTime < dateadd(d, 1,'2016-01-13')
)
select
x.Id,
x.DateTime,
x.Import,
x.Export,
x.Total,
case when x.[QualifyingImports] > 2 then (x.MinQualifyingImport - 1000) * 200 else (x.MinQualifyingImport - 1000) * 100 end as [Rate]
from x
I've put together a Fiddle so you can play around with different values for Id # 4.
I really wanted to make the values of things like threshold and period into #variables, but it doesn't appear to be supported inside CTEs so I just had to hard code them.
EDIT
Turns out the CTE is overkill, you can shrink it down to this and use #variables, yay!
declare #period smalldatetime = '2016-01-13'
declare #threshold float = 1000
declare #rate1 float = 100
declare #rate2 float = 200
select
t1.Id,
t1.DateTime,
t1.Import,
t1.Export,
t1.Total,
case
when count(t2.Import) over (partition by 1) > 2 then (min(t2.Import) over (partition by 1) - #threshold) * #rate2
else (min(t2.Import) over (partition by 1) - #threshold) * #rate1
end as [Rate]
from
myTable t1
left join myTable t2 on t2.Import > #threshold and t2.Id = t1.Id
where
t1.DateTime >= #period
and t1.DateTime < dateadd(d, 1, #period)
New Fiddle