SQL server View - loop help (while loop) - sql

I've been asked to produce a dataset using a view in SQL and have a number of products (eg 'a a','b b','c c') and I want to work out totals over 5 years (1,2,3,4,5) and output the totals as total_a_a_yr1, total_b_b_yr1....(see the below code)
Rather than writing out loads of lines of code is there a more efficient way of coding?
I thought about creating a procedure but I don't think you can use an EXEC within a view. I may be wrong. A while loop might be the way to go but I'm unsure about using declares in views.
Any help would be appreciated. Thanks
,sum(case when product = 'a a' and floor(datediff(dd, date1,date2)/365.25)<1
then amount_received else null end) as total_a_a_yr1
,sum(case when product = 'a a' and floor(datediff(dd, date1,date2)/365.25)<(2)
then amount_received else null end) as total_a_a_yr2
,sum(case when product = 'a a' and floor(datediff(dd, date1,date2)/365.25)<(3)
then amount_received else null end) as total_a_a_yr3
,sum(case when product = 'a a' and floor(datediff(dd, date1,date2)/365.25)<(4)
then amount_received else null end) as total_a_a_yr4
,sum(case when product = 'a a' and floor(datediff(dd, date1,date2/365.25)<(5)
then amount_received else null end) as total_a_a_yr5

First, the default value for a case statement is NULL so, "ELSE NULL" is not necessary. Second, this formula is probably not doing exactly what you think: floor(datediff(dd, date1,date2)/365.25). What I mean is, if you are operating under the assumption that there is a leap year every four years, you are incorrect. Leap years don't happen on years divisible by 100 UNLESS it can also be divided by 400. I could be misunderstanding what you're trying to do however.
You're correct, You can't use dynamic SQL (e.g. EXEC '<sql code>') in a view. There's very little you can't do with a tally table. Here's how you'd generate your code programatically using a tally table (I'm going to 1 to 100):
with yourExpression(ex) as
(
select ',sum(case when product = ''''a a'''' and floor(datediff(dd, date1,date2)/365.25)<
then amount_received else null end) as total_a_a_yr'
),
iTally(N) as
(
select top(100) cast(row_number() over (order by (select null)) as varchar(3))
from sys.all_columns
)
select stuff(ex,78,0,'('+N+')')+N
from iTally
cross join yourExpression;
You can copy/paste and execute the query as is; it will return:
,sum(case when product = ''a a'' and floor(datediff(dd, date1,date2)/365.25)<(1)
then amount_received else null end) as total_a_a_yr1
,sum(case when product = ''a a'' and floor(datediff(dd, date1,date2)/365.25)<(2)
then amount_received else null end) as total_a_a_yr2
,sum(case when product = ''a a'' and floor(datediff(dd, date1,date2)/365.25)<(3)....
--<truncated for brevity> ... as total_a_a_yr100

Related

Case statement - cannot nest aggregate operations

I am getting an error -
can not nest aggregate operations when trying to run the below part of the query in Teradata.
When SeqCount = 2 and surgery data is the same as the first surgery, I want the 2nd surgery date (SecondSurgery) to be null else return the 2nd surgery data.
Any help would be greatly appreciated.
SELECT
pat_id,
PatientMRN,
PatientName,
AdmitDate,
DischargeDate,
MIN(case when SeqCount=1 then ORProcName else null end) as FirstProcedure,
MIN(case when SeqCount=1 then SurgeryDate else null end) as FirstSurgery,
MIN(case when SeqCount=2 then ORProcName else null end) as SecondProcedure,
MIN(case when SeqCount=2 and SurgeryDate = FirstSurgery then NULL else SurgeryDate end) as SecondSurgery
as the ErrorMsg is saying it's not possible due to the SET-based processing (all at once). - You can force an sequential processing with sub-queries and calculate SecondSurgery in the outer-SQL.

Transact SQL - Table with different Record types requiring calculation

I have a table of invoices and Record_Types that I need to reconcile to open invoice report. I have the process down and know what I need to do. Just dont know how to properly structure the query and would prefer to not create 3 tables.
Record Types.
Invoice = 1 Credit = 5 Payment = 7
Invoice_Number, Record_Type, Dollar figure
Outstanding_Balance = Invoice(1) -(Payment(7)-(Credit))
Invoice_number Record_type Gen_Numeric_3
Basically I need to take the record_Type 1 and subtract the total of record type 7's from the below.
Invoice_Num Rec_Type Dollar_Amt
00820437 1 536.7700000000
00820437 7 469.6200000000
00820437 7 67.1500000000
Any advice would be great. messer
You can do this with aggregation and case statements:
SELECT invoice_num,
SUM(CASE WHEN rec_type = 1 THEN dollar_amt ELSE 0 END) - (SUM(CASE WHEN rec_type=7 THEN dollar_amt ELSE 0 END) - SUM(CASE WHEN rec_type=5 THEN dollar_amt ELSE 0 END)) as outstanding_balance
FROM yourtable
GROUP BY invoice_num

SQL select grouping and subtract

i have table named source table with data like this :
And i want to do query that subtract row with status plus and minus to be like this group by product name :
How to do that in SQL query? thanks!
Group by the product and then use a conditional SUM()
select product,
sum(case when status = 'plus' then total else 0 end) -
sum(case when status = 'minus' then total else 0 end) as total,
sum(case when status = 'plus' then amount else 0 end) -
sum(case when status = 'minus' then amount else 0 end) as amount
from your_table
group by product
There is another method using join, which works for the particular data you have provided (which has one "plus" and one "minus" row per product):
select tplus.product, (tplus.total - tminus.total) as total,
(tplus.amount - tminus.amount) as amount
from t tplus join
t tminus
on tplus.product = tminus.product and
tplus.status = 'plus' and
tplus.status = 'minus';
Both this and the aggregation query work well for the data you have provided. In other words, there are multiple ways to solve this problem (each has its strengths).
you can query as below:
select product , sum (case when [status] = 'minus' then -Total else Total end) as Total
, sum (case when [status] = 'minus' then -Amount else Amount end) as SumAmount
from yourproduct
group by product

Possible to do math inside of a sum statement?

I'm by no means an expert in DB2 so apologies if this is a novice question. I am looking for a specific requirement. I am summing through a table based on a case statement but am wondering if we could subtract an amount if a field is present in the row.
SELECT CODE,
SUM(CASE SUBSTR(DATE,4,2)
WHEN '01' THEN AMT
END) as JanuaryTotal
FROM Table1
I'm looking to see if we can simply, if another field is present, if we can instead of summing it, simply subtract it from the total that is currently in place.
SELECT CODE,
SUM(CASE SUBSTR(DATE,4,2)
WHEN '01' THEN CASE WHEN TYPE = 'X'
THEN - AMT // some possible way to do this?
ELSE AMT
END) as JanuaryTotal
FROM Table1
Again, apologies. i know this code doesnt run but just giving a visual of something to see if it's possible to do.
SELECT CODE, SUM(
CASE
WHEN SUBSTR(DATE,4,2) = '01' THEN AMT
WHEN TYPE = 'X' THEN 0 - AMT
ELSE AMT
END
) as JanuaryTotal
FROM Table1
Sometimes it helps to indent. Also, it is not quite clear what to do if the sub-string is not 01 -- I'm guessing you don't want to add anything.
SELECT CODE,
SUM(CASE SUBSTR(DATE,4,2)
WHEN '01' THEN
CASE
WHEN TYPE = 'X' THEN -1 * AMT
ELSE AMT
END
ELSE 0 -- SUBSTR(DATE,4,2) is not '01'
END) as JanuaryTotal
FROM Table1
The simplest final query is to flatten out your conditions so they stand alone:
SELECT CODE, SUM(CASE
WHEN SUBSTR(DATE,4,2) AND TYPE = 'X' THEN 0-AMT
WHEN SUBSTR(DATE,4,2) AND THEN AMT END) as JanuaryTotal
FROM Table1
Note that there are two forms of CASE:
CASE <expression>
WHEN <value> THEN ...
WHEN <value> THEN ...
and
CASE
WHEN <condition> THEN ...
WHEN <condition> THEN ...
I switched your query from using the first form to the second form.
SELECT CODE, SUM(
CASE
WHEN SUBSTR(DATE,4,2) = '01' and TYPE = 'X' THEN -AMT
else AMT
END
) as JanuaryTotal
FROM Table1
group by CODE

SQL Division returning odd value

So Basically I have two sum values, that I return. I then divide one of them by the other, my goal was to get spit out a basic value. However the Value that is returned is all over the place.
I assume I screwed up the "Cast" but I am not sure here.
It would be impossible for me to share the entirety of the SQL that generates this. I will focus on the end results here which start with an Outer Apply:
This is me calling the Outer apply values for display, and then my attempt at dividing them:
,VerifyBlock.Numa as [Numerator]
,VerifyBlock.Denominator
,(isNull(((VerifyBlock.Numa) / NullIF(VerifyBlock.Denominator,0)),0)) as [Division]
This is the outer apply that generates the above:
OUTER APPLY (SELECT CASE WHEN CAST(tmpdc2.[14]AS decimal(10,2)) <= 0 AND (CASE WHEN T4MathBlock.[Value] >0 THEN T4MathBlock.[Value]
ELSE '0.00' END)<= 0
THEN '0.00'
ELSE (CASE WHEN CAST(tmpdc2.[14]AS decimal(10,2)) < (CASE WHEN T4MathBlock.[Value] >0 THEN T4MathBlock.[Value]
ELSE '0.00' END) THEN CAST(tmpdc2.[14]AS decimal(10,2))
ELSE (CASE WHEN T4MathBlock.[Value] >0 THEN T4MathBlock.[Value]
ELSE '0.00' END) End)
END AS [Amount]
From ##TempDisclosure tmpdc2
WHERE tmpdc1.[Student Number] = Tmpdc2.[Student Number]
)[AF]
WHERE tmpdc1.[Student Number] = Tmpdc.[Student Number]
)[VerifyBlock]
Sorry if the formatting is wonky.
I know the Values generated by:
VerifyBlock.Numa and VerifyBlock.Denominator are solid. The values they return are
32747682.64 and 78740189.20 (Respectively)
The Division though returns: 947860.602435
When it should actually return: 0.4158954019886963
So where the heck did I go wrong here?