Quarterly totals using loop in SQL server - sql

----I am trying to get yearly and quarterly totals for 2013 and 2014 for San Francisco and San mateo counties seperately. I know it is probably very easy but having difficulty with the loop. I can do it without looping but it is lengthy and would like to do it in a cleaner neater fashion. Any help would be greatly appreciated. New to programming------
DECLARE #Qtotal int
DECLARE #Q1total int
DECLARE #Q2total int
DECLARE #Q3total int
DECLARE #Q4total int
DECLARE #year int
DECLARE #County int
DECLARE #CountyName varchar(40)
DECLARE #startmonth nvarchar
DECLARE #endmonth nvarchar
SET #startmonth = '1'
SET #endmonth = '3'
SET #year = '2013'
SET #county = '038'
SET #countyName = 'San Francisco'
Begin
SELECT #Qtotal = (select COUNT(*) FROM #tCounty
where year(cast(dDate as date)) = #year
and countycode = #County
and month(cast(deathDate as date)) between #startmonth and #endmonth)--get quarter total
if #startmonth=1 SET #Q1total = #Qtotal
if #startmonth=4 SET #Q2total = #Qtotal
if #startmonth=7 SET #Q3total = #Qtotal
if #startmonth=10 SET #Q4total = #Qtotal
Set #startmonth = #startmonth + 3
Set #startmonth = #endmonth + 3
if #startmonth > 10
end
--------insert into table created before and not shown in code above
INSERT INTO #Totals([County],[referenceYear],[Total],[Q1],[Q2],[Q3],[Q4]) Values (#countyName,#year,#yrtotal,#Q1total,#Q2total,#Q3total,#Q4total)

this should do it
select County,
Year(dDate) as Year,
count(*) as Total,
sum(case when DATEPART(q, dDate)=1 then 1 else 0 end) as Q1,
sum(case when DATEPART(q, dDate)=2 then 1 else 0 end) as Q2,
sum(case when DATEPART(q, dDate)=3 then 1 else 0 end) as Q3,
sum(case when DATEPART(q, dDate)=4 then 1 else 0 end) as Q4
from #tCounty
group by County,
Year(dDate)

Related

Calculating RSI for Multiple Dates and Tickers in SQL Server 2012

I can calculate RSI for a specific end date:
DECLARE #StartingDate smalldatetime
DECLARE #EndingDate smalldatetime
DECLARE #StockID char(15)
DECLARE #DAYS INT
DECLARE #AG FLOAT
DECLARE #AL FLOAT
DECLARE #RS FLOAT
SET #StartingDate = '20180301'
SET #EndingDate = '20180403'
SET #StockID = 'ACE'
SET #DAYS = 14
SET #AG =(
SELECT SUM([px_close]-[px_open])
FROM [dbo].[daily_data]
WHERE [Ticker] = #STOCKID
AND ([Date] BETWEEN #StartingDate AND #EndingDate)
AND ([px_close]-[px_open])>0)/#DAYS
SET #AL =(
SELECT SUM([px_close]-[px_open])
FROM [dbo].[daily_data]
WHERE [Ticker] = #STOCKID
AND ([Date] BETWEEN #StartingDate AND #EndingDate)
AND ([px_close]-[px_open])<0)/#DAYS
SET #RS = #AG/ABS(#AL)
SELECT #StockID AS Ticker, #EndingDate AS Date, 100 - (100/(1+#RS)) RSI
Here's my output:
Ticker Date RSI
ACE 2018-04-03 48.7307
How can I calculate RSI for multiple dates and multiple tickers?
You don't need to set all of these to variables. You can just add the date and ticker to the group by and avoid the redundant subqueries... something like:
SELECT
[Ticker]
,[Date]
,AG = SUM(case when (isnull([px_close],0)-isnull([px_open],0))>0 then (isnull([px_close],0)-isnull([px_open],0)) end) / #days
,AL = SUM(case when (isnull([px_close],0)-isnull([px_open],0))<0 then (isnull([px_close],0)-isnull([px_open],0)) end) / #days
,RS = (SUM(case when (isnull([px_close],0)-isnull([px_open],0))>0 then (isnull([px_close],0)-isnull([px_open],0)) end) / #days) / ABS(SUM(case when (isnull([px_close],0)-isnull([px_open],0))<0 then (isnull([px_close],0)-isnull([px_open],0)) end) / #days)
,RSI = 100 - (100/(1+(SUM(case when (isnull([px_close],0)-isnull([px_open],0))>0 then (isnull([px_close],0)-isnull([px_open],0)) end) / #days) / ABS(SUM( case when (isnull([px_close],0)-isnull([px_open],0))<0 then (isnull([px_close],0)-isnull([px_open],0)) end) / #days)))
FROM
[dbo].[daily_data]
WHERE
[Ticker] = #STOCKID
AND ([Date] BETWEEN #StartingDate AND #EndingDate)
group by
[Ticker],[Date]
Remove [Ticker] = #STOCKID from the where clause to return all Tickers

Setting Variables in IF statements in SQL Server 2014

Msg 134, Level 15, State 1, Line 21
The variable name '#AsOfDate' has already been declared. Variable names must be unique within a query batch or stored procedure.
I am getting this error when running a set of IF statements. Ideally I would simply need to toggle my bit to 1 for the quarter I'm interested in and then execute my code. The IF statements would set the dates I need.
I have tried this with IF and ELSE IF, but neither seems to make a difference. Any suggestions on how I can do this would be greatly appreciated. Sadly I can't simply have it pick the quarter I'm in (or the one previous) as these reports may be requested at any time.
-------------------------
-- Choose Quarter --
-------------------------
DECLARE #Q1 BIT = 0
DECLARE #Q2 BIT = 0
DECLARE #Q3 BIT = 0
DECLARE #Q4 BIT = 0
DECLARE #Annual BIT = 0
-------------------------
--Q1
IF #Q1 = '1'
BEGIN
DECLARE #AsOfDate datetime = '2016-03-31';
DECLARE #StartDate datetime = '2016-01-01'
END
--Q2
IF #Q2 = '1'
BEGIN
DECLARE #AsOfDate datetime = '2016-06-30';
DECLARE #StartDate datetime = '2016-04-01'
END
--Q3
IF #Q3 = '1'
BEGIN
DECLARE #AsOfDate datetime = '2016-09-30';
DECLARE #StartDate datetime = '2016-07-01'
END
--Q4
IF #Q4 = '1'
BEGIN
DECLARE #AsOfDate datetime = '2016-12-31';
DECLARE #StartDate datetime = '2016-10-01'
END
-- ANNUAL
IF #Annual = '1'
BEGIN
DECLARE #AsOfDate datetime = '2016-12-31';
DECLARE #StartDate datetime = '2016-01-01'
END
-- Check to ensure a time period is set
IF (#Q1 = 0 AND #Q2 = 0 AND #Q3 = 0 AND #Q4 = 0 AND #ANNUAL = 0)
BEGIN
PRINT 'NO TIME SET'
END
-- Run Code with dates
ELSE
BEGIN
EDIT:
Disregard... actually reading my error and code clearly points to my declares being an issue not the setting of the variable... Solution is to declare the variables outside of my IF statements and SET them in the statement.
I was declaring in each IF statement instead of declaring prior to all the IF statements. Below is the updated version of the code.
DECLARE #ASOfDate DATETIME
DECLARE #StartDate DATETIME
-------------------------
-- Choose Quarter --
-------------------------
DECLARE #Q1 BIT = 0
DECLARE #Q2 BIT = 0
DECLARE #Q3 BIT = 0
DECLARE #Q4 BIT = 0
DECLARE #Anual BIT = 0
-------------------------
--Q1
IF #Q1 = '1'
BEGIN
SET #AsOfDate = '2016-03-31' ; SET #StartDate = '2016-01-01'
END
--Q2
IF #Q2 = '1'
BEGIN
SET #AsOfDate = '2016-06-30' ; SET #StartDate = '2016-04-01'
END
--Q3
IF #Q3 = '1'
BEGIN
SET #AsOfDate = '2016-09-30' ; SET #StartDate = '2016-07-01'
END
--Q4
IF #Q4 = '1'
BEGIN
SET #AsOfDate = '2016-12-31' ; SET #StartDate = '2016-10-01'
END
--ANUAL
IF #Anual = '1'
BEGIN
SET #AsOfDate = '2016-12-31' ; SET #StartDate = '2016-01-01'
END
-- Check to ensure a time period is set
IF (#Q1 = 0 AND #Q2 = 0 AND #Q3 = 0 AND #Q4 = 0 AND #ANUAL = 0)
BEGIN
PRINT 'NO TIME SET'
END
-- Run Code with dates
ELSE
BEGIN
Start of Actual Program using dates shown
END

Code error in a SQL Server While-If Loop

I know that there are other posts with code that solve my problem but I don't want to take another's code so I'm trying to do it by myself and I'm stuck with the month not increasing problem, so if anyone can help me with that mistake it will be awesome.
The problem is:
I have to populate the table Time from year 1990 to 2016 with all the months and days, I have already achieved that the code works and it populates correctly the years and the days but months increases to January (1) and then is not increasing so the table is filled with all months being January (LOL)
Here's my code:
create table Time
(
Year int,
Month int,
Day int
)
create procedure pTime
as
declare #year int, #month int, #day int;
set #year = 1990;
set #month = 12;
set #day = 10;
while(#year<=2016)
Begin
If(#day = 29)
Begin
set #month = #month + 1;
If(#month = 13)
Begin
set #month = 1;
set #day = 1;
set #year = #year + 1;
insert into Time values (#year, #month, #day);
End
End
else
Begin
If(#day = 29)
Begin
set #month = #month + 1;
set #day = 1;
insert into Time values (#year, #month, #day);
End
Else
Begin
insert into Time values (#year, #month, #day);
set #day = #day + 1;
End
End
End
Any idea where is my mistake or any suggestion?
I didn't look very closely for your mistake because SQL Server has some helpful date arithmetic functions. Here's simplified version of your stored procedure:
create procedure pTime
as
declare #theDate date = '12/10/1990', #days int = 0
while #theDate < '1/1/2016'
begin
insert into Time (Year, Month, Day) values (datepart(year, #theDate), datepart(month, #theDate), datepart(day, #theDate));
set #theDate = dateadd(day, 1, #theDate)
end
Another faster approach would be to use a tally table. Note the code below:
WITH
E(N) AS (SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1),
iTally(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1))-1 FROM E a,E b,E c,E d,E e),
dates(dt) AS
(
SELECT TOP(datediff(DAY,'19900101','20160101')) DATEADD(day,N,'19900101')
FROM iTally
)
--INSERT [time] --uncomment for the insert, leave commented to see what will be inserted
SELECT YEAR(dt), MONTH(dt), DAY(dt)
FROM dates;
Why do you need If(#year = 29) condition? In your code this block never will be executed. try this:
create procedure pTime
as
declare #year int, #month int, #day int;
set #year = 1990;
set #month = 12;
set #day = 10;
while(#year<=2016)
Begin
If(#day = 29)
Begin
set #month = #month + 1;
set #day = 1;
If(#month = 13)
Begin
set #month = 1;
set #year = #year + 1;
insert into Time values (#year, #month, #day);
End
End
else
Begin
If(#day = 29)
Begin
set #month = #month + 1;
set #day = 1;
insert into Time values (#year, #month, #day);
End
Else
Begin
insert into Time values (#year, #month, #day);
set #day = #day + 1;
End
End
End
I think first assignment set #day = 1; wasn't in right place. After increasing #month value you should set also #day to 1;

Changing a variable value within a query in SQL 2008

If someone can help me with this, I will appreciate it.
I have 2 tables in sql 2008:
[users]
[userId] uniqueidentifier
[beginningDate] datetime
and [items]
[userId] uniqueidentifier
[itemDate] datetime
I want to count the number of users that have at least one item in [items] from January to December of any given year, I do this:
DECLARE #Year int = 2014, #Month int = 1 --January
SELECT ISNULL(Count(*), 0)
FROM [users]
WHERE
(
SELECT ISNULL(Count(*), 0) FROM [items]
WHERE [users].[userId] = [items].[userId]
AND YEAR([itemDate]) = #Year
AND ( MONTH([itemDate]) >= #Month AND MONTH([itemDate]) <= 12 )
) > 0
It works fine, the problem is that I want to check (and change accordingly), if the [beginningDate] is newer than #Month /#Year (it will always be the same year) then change the #Month variable to the [beginningDate] month value.
Thank to Allan S. Hansen for his reply.
I solved the problem by creating a function and calling it from my query:
CREATE FUNCTION [dbo].[GetMonth]
(
#UserId uniqueidentifier
, #Year int
)
RETURNS int
AS
BEGIN
DECLARE #Month int = 1; --January
DECLARE #DateValue DateTime
DECLARE #DateFrom DateTime = CONVERT(nvarchar(4), #Year) +'-03-01' --de mar
SELECT #DateValue =
CASE
WHEN [beginningDate] > #DateFrom THEN [beginningDate]
ELSE #DateFrom
END
FROM [users]
WHERE [userId] = #UserId
IF(#DateValue IS NULL)
SET #Month = 1;
ELSE
IF(#DateValue > #DateFrom) SET #Month = MONTH(#DateValue)
return #Month;
END
This is the new query:
DECLARE #Year int = 2014, #Month int = 1 --January
SELECT ISNULL(Count(*), 0)
FROM [users]
WHERE
(
SELECT ISNULL(Count(*), 0) FROM [items]
WHERE [users].[userId] = [items].[userId]
AND YEAR([itemDate]) = #Year
AND ( MONTH([itemDate]) >= [dbo].[GetMonth] ([users].[userId], #Year)
AND MONTH([itemDate]) <= 12 )
) > 0
Thanks anyway to all
Saludos
rubenc

SQL Case Statement with math in Where Clause

I have the following query
DECLARE #onlymonth bit
SET #onlymonth = 0
DECLARE #month int
SET #month = 5
SELECT
SUM(amount) amount
FROM accounting ac
WHERE
DATEPART(mm,ac.date) <= #month
What I want is depending on the #onlymonth parameter remove the minor sign so... for example
...WHERE
DATEPART(mm,ac.date) = CASE WHEN #onlymonth = 0 THEN = #month ELSE <= #month END...
Something like that.. any clue?
Thanks in advance.
Try this:
SELECT
SUM(amount) amount
FROM
accounting ac
WHERE
(DATEPART(mm,ac.date) = #month and #onlymonth = 0)
OR
(DATEPART(mm,ac.date) <= #month and #onlymonth = 1)
This does what you want.
DECLARE #onlymonth bit
SET #onlymonth = 0
DECLARE #month int
SET #month = 5
if (#onlymonth = 0)
begin
SELECT
SUM(amount) amount
FROM accounting ac
WHERE
DATEPART(mm,ac.date) <= #month
end
else
begin
SELECT
SUM(amount) amount
FROM accounting ac
WHERE
DATEPART(mm,ac.date) = #month
end
Alternative approach:
declare #month int, #bSingleMonth bit
set #month = 7
set #bSingleMonth = 1
SELECT SUM(amount) amount
FROM accounting ac
WHERE DATEPART(mm, ac.date)
between 1 + IsNull(#bSingleMonth, 0) * (#month - 1) and #month
this makes it between #month and #month when #bSingleMonth is set and between 1 and #month when it is not.