Aggregate totals in TSQL select error msg 116 - tsql

I have 5 balance fields possible for one loan records. I need to total these fields while excluding those columns per loan record that contain a specific code.
Here is an example of the data record, each total field has a corresponding code. I want to sum all totals and exclue the "X" code total.
The code "X" can be attached to any total column, in this case it just happens to be at the end.
loan number | total 1 | total 2 | total 3 | total 4 |total 5 | code1 | code2 | code3 | code4 | code5
123456789 | 12.50 | 1,950.43 | 750.00 | | 275.98 | A | B | C | | X
Here is my subquery in an existing TSQL query:
, (SELECT [CMI ACCOUNT],
[Unapplied Funds 1 - Balance] = SUM (CASE WHEN [UNAPPLIED code 1] = 'L' THEN 0 ELSE ISNULL( [UNAPPLIED BALANCE 1], 0) end
+ CASE WHEN [UNAPPLIED code 2] = 'L' THEN 0 ELSE ISNULL( [UNAPPLIED BALANCE 2], 0) end
+ CASE WHEN [UNAPPLIED code 3] = 'L' THEN 0 ELSE ISNULL( [UNAPPLIED BALANCE 3], 0) end
+ CASE WHEN [UNAPPLIED code 4] = 'L' THEN 0 ELSE ISNULL( [UNAPPLIED BALANCE 4], 0) end
+ CASE WHEN [UNAPPLIED code 5] = 'L' THEN 0 ELSE ISNULL( [UNAPPLIED BALANCE 5], 0) end)
FROM CIT_UNAPPLIED
GROUP BY [CMI ACCOUNT]
)
Unfortunately, this gives me an error message stating:
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.

The Error message suggests that the subquery is in the Select list or the WHERE clause
It should be part of from clause
SELECT
b.[CMI ACCOUNT],
b.[Unapplied Funds 1 - Balance]
FROM
(
SELECT [CMI ACCOUNT],
[Unapplied Funds 1 - Balance] = SUM (CASE WHEN [UNAPPLIED code 1] = 'L' THEN 0 ELSE ISNULL( [UNAPPLIED BALANCE 1], 0) end
+ CASE WHEN [UNAPPLIED code 2] = 'L' THEN 0 ELSE ISNULL( [UNAPPLIED BALANCE 2], 0) end
+ CASE WHEN [UNAPPLIED code 3] = 'L' THEN 0 ELSE ISNULL( [UNAPPLIED BALANCE 3], 0) end
+ CASE WHEN [UNAPPLIED code 4] = 'L' THEN 0 ELSE ISNULL( [UNAPPLIED BALANCE 4], 0) end
+ CASE WHEN [UNAPPLIED code 5] = 'L' THEN 0 ELSE ISNULL( [UNAPPLIED BALANCE 5], 0) end
FROM CIT_UNAPPLIED
GROUP BY [CMI ACCOUNT]
) b
You can join that subquery to other Tables, views or subqueries as you would a normal table
SELECT
a.[Account Name],
b.[CMI ACCOUNT],
b.[Unapplied Funds 1 - Balance]
FROM
Another Table a
JOIN
(
SELECT [CMI ACCOUNT],
[Unapplied Funds 1 - Balance] = SUM (CASE WHEN [UNAPPLIED code 1] = 'L' THEN 0 ELSE ISNULL( [UNAPPLIED BALANCE 1], 0) end
+ CASE WHEN [UNAPPLIED code 2] = 'L' THEN 0 ELSE ISNULL( [UNAPPLIED BALANCE 2], 0) end
+ CASE WHEN [UNAPPLIED code 3] = 'L' THEN 0 ELSE ISNULL( [UNAPPLIED BALANCE 3], 0) end
+ CASE WHEN [UNAPPLIED code 4] = 'L' THEN 0 ELSE ISNULL( [UNAPPLIED BALANCE 4], 0) end
+ CASE WHEN [UNAPPLIED code 5] = 'L' THEN 0 ELSE ISNULL( [UNAPPLIED BALANCE 5], 0) end
FROM CIT_UNAPPLIED
GROUP BY [CMI ACCOUNT]
) b
ON a.[CMI ACCOUNT]=b.[CMI ACCOUNT]
Depending on what you want the rest of your query to do

Related

How to add a query with where date condition in a arrayformula?

I need to add a query in arrayformula.
My data:
A
B
C
D
E
F
1
DATE
ITEM
TRANSACTION
PRICE
QTY
ARRAYFORMULA???
2
2021/06/30
aaaa
verify
14.00
1
74.00 ((5-0)*14+4)
3
2021/06/30
bbbb
verify
10.00
1
202.00 ((40-20)*10+2)
4
2021/06/30
bbbb
sell
15.00
20
-
5
2021/06/10
aaaa
received
4.00
1
-
6
2021/05/31
aaaa
verify
10.00
1
50.00 ((5-0)*10+0)
7
2021/05/31
bbbb
verify
8.00
1
322.00 ((40-0)*8+2)
8
2021/05/20
bbbb
received
2.00
1
-
9
2021/05/10
bbbb
buy
8.00
40
-
10
2021/05/09
aaaa
buy
11.00
5
-
Basically I need in column F: if transaction is "verify", return the value received for that item PLUS the PRODUCT between the quantity in stock (column E where column C is "buy" MINUS column E where column C is "sell") and the current price (column D) until that date.
I think I need 3 queries: one for received values, another for quantity bought and the last for quantity sold. I'm stuck in the first query:
=SUM(QUERY(A2:E;"SELECT SUM(D) WHERE A <= date '"&TEXT(DATEVALUE(A2);"yyyy-mm-dd")&"' AND C = 'received' AND B = '"&B2&"'"))
Another approach:
=vlookup(B2;QUERY(A2:E;"SELECT B, SUM(D) WHERE A <= date '"&TEXT(DATEVALUE(A2);"yyyy-mm-dd")&"' AND C = 'received' AND B = '"&B2&"' group by B");2;false)+(vlookup(B2;QUERY(A2:E;"SELECT B, SUM(E) WHERE A <= date '"&TEXT(DATEVALUE(A2);"yyyy-mm-dd")&"' AND C = 'buy' AND B = '"&B2&"' group by B");2;false)-iferror(vlookup(B2;QUERY(A2:E;"SELECT B, SUM(E) WHERE A <= date '"&TEXT(DATEVALUE(A2);"yyyy-mm-dd")&"' AND C = 'sell' AND B = '"&B2&"' group by B");2;false);0))*D2
I can't add this in a arrayformula (cell F1). Btw I need a arrayformula because I have a lot of data.
Sorry my English. Thanks for your help!
try:
={"ARRAYFORMULA"; ARRAYFORMULA(IFNA((VLOOKUP(COUNTIFS(C2:C, C2:C, C2:C, "verify", ROW(C2:C), "<="&ROW(C2:C))&"♦"&B2:B&"♦buy", QUERY(SPLIT(FLATTEN(IFERROR(SEQUENCE(COUNTIF(C:C, "verify"))&"♦"&VLOOKUP(
IF(SEQUENCE(COUNTIF(C:C, "verify"), COUNTA(C:C))-(SEQUENCE(COUNTIF(C:C, "verify"), 1, 0)*COUNTA(C:C))>FILTER(ROW(A:A), C:C="verify"), SEQUENCE(1, COUNTA(C:C)), )&FILTER(B:B, C:C="verify"),
{ROW(A:A)&B:B, B:B&"♦"&C:C&"×"&D:D&"×"&E:E}, 2, 0))), "×"), "select Col1,sum(Col2),sum(Col3) where Col2 is not null group by Col1"), 3, 0)-
IFNA(VLOOKUP(COUNTIFS(C2:C, C2:C, C2:C, "verify", ROW(C2:C), "<="&ROW(C2:C))&"♦"&B2:B&"♦sell", QUERY(SPLIT(FLATTEN(IFERROR(SEQUENCE(COUNTIF(C:C, "verify"))&"♦"&VLOOKUP(
IF(SEQUENCE(COUNTIF(C:C, "verify"), COUNTA(C:C))-(SEQUENCE(COUNTIF(C:C, "verify"), 1, 0)*COUNTA(C:C))>FILTER(ROW(A:A), C:C="verify"), SEQUENCE(1, COUNTA(C:C)), )&FILTER(B:B, C:C="verify"),
{ROW(A:A)&B:B, B:B&"♦"&C:C&"×"&D:D&"×"&E:E}, 2, 0))), "×"), "select Col1,sum(Col2),sum(Col3) where Col2 is not null group by Col1"), 3, 0), 0))*
IF(C2:C="verify", D2:D, )+
IFNA(VLOOKUP(COUNTIFS(C2:C, C2:C, C2:C, "verify", ROW(C2:C), "<="&ROW(C2:C))&"♦"&B2:B&"♦received", QUERY(SPLIT(FLATTEN(IFERROR(SEQUENCE(COUNTIF(C:C, "verify"))&"♦"&VLOOKUP(
IF(SEQUENCE(COUNTIF(C:C, "verify"), COUNTA(C:C))-(SEQUENCE(COUNTIF(C:C, "verify"), 1, 0)*COUNTA(C:C))>FILTER(ROW(A:A), C:C="verify"), SEQUENCE(1, COUNTA(C:C)), )&FILTER(B:B, C:C="verify"),
{ROW(A:A)&B:B, B:B&"♦"&C:C&"×"&D:D&"×"&E:E}, 2, 0))), "×"), "select Col1,sum(Col2),sum(Col3) where Col2 is not null group by Col1"), 2, 0), 0)))}
non-english locale:
={"ARRAYFORMULA"; ARRAYFORMULA(IFNA((VLOOKUP(COUNTIFS(C2:C; C2:C; C2:C; "verify"; ROW(C2:C); "<="&ROW(C2:C))&"♦"&B2:B&"♦buy"; QUERY(SPLIT(FLATTEN(IFERROR(SEQUENCE(COUNTIF(C:C; "verify"))&"♦"&VLOOKUP(
IF(SEQUENCE(COUNTIF(C:C; "verify"); COUNTA(C:C))-(SEQUENCE(COUNTIF(C:C; "verify"); 1; 0)*COUNTA(C:C))>FILTER(ROW(A:A); C:C="verify"); SEQUENCE(1; COUNTA(C:C)); )&FILTER(B:B; C:C="verify");
{ROW(A:A)&B:B\ B:B&"♦"&C:C&"×"&D:D&"×"&E:E}; 2; 0))); "×"); "select Col1,sum(Col2),sum(Col3) where Col2 is not null group by Col1"); 3; 0)-
IFNA(VLOOKUP(COUNTIFS(C2:C; C2:C; C2:C; "verify"; ROW(C2:C); "<="&ROW(C2:C))&"♦"&B2:B&"♦sell"; QUERY(SPLIT(FLATTEN(IFERROR(SEQUENCE(COUNTIF(C:C; "verify"))&"♦"&VLOOKUP(
IF(SEQUENCE(COUNTIF(C:C; "verify"); COUNTA(C:C))-(SEQUENCE(COUNTIF(C:C; "verify"); 1; 0)*COUNTA(C:C))>FILTER(ROW(A:A); C:C="verify"); SEQUENCE(1; COUNTA(C:C)); )&FILTER(B:B; C:C="verify");
{ROW(A:A)&B:B\ B:B&"♦"&C:C&"×"&D:D&"×"&E:E}; 2; 0))); "×"); "select Col1,sum(Col2),sum(Col3) where Col2 is not null group by Col1"); 3; 0); 0))*
IF(C2:C="verify"; D2:D; )+
IFNA(VLOOKUP(COUNTIFS(C2:C; C2:C; C2:C; "verify"; ROW(C2:C); "<="&ROW(C2:C))&"♦"&B2:B&"♦received"; QUERY(SPLIT(FLATTEN(IFERROR(SEQUENCE(COUNTIF(C:C; "verify"))&"♦"&VLOOKUP(
IF(SEQUENCE(COUNTIF(C:C; "verify"); COUNTA(C:C))-(SEQUENCE(COUNTIF(C:C; "verify"); 1; 0)*COUNTA(C:C))>FILTER(ROW(A:A); C:C="verify"); SEQUENCE(1; COUNTA(C:C)); )&FILTER(B:B; C:C="verify");
{ROW(A:A)&B:B\ B:B&"♦"&C:C&"×"&D:D&"×"&E:E}; 2; 0))); "×"); "select Col1,sum(Col2),sum(Col3) where Col2 is not null group by Col1"); 2; 0); 0)))}
#Max Makhrov posted an answer is this link using "MMULT(TRANSPOSE(" to FILTER in ARRAYFORMULA. I solved my question with the below arrayformula (link):
={"ARRAYFORMULA";ARRAYFORMULA(IF(C2:C<>"verify";"";MMULT(--(TRANSPOSE(A2:A)<=A2:A)*(TRANSPOSE(B2:B)=B2:B)*(TRANSPOSE(C2:C)="received");if(D2:D="";0;D2:D))+if(D2:D="";0;D2:D)*(MMULT(--(TRANSPOSE(A2:A)<=A2:A)*(TRANSPOSE(B2:B)=B2:B)*(TRANSPOSE(C2:C)="buy");if(E2:E="";0;E2:E))-MMULT(--(TRANSPOSE(A2:A)<=A2:A)*(TRANSPOSE(B2:B)=B2:B)*(TRANSPOSE(C2:C)="sell");if(E2:E="";0;E2:E)))))}

Selecting data from 2 specific dates gives "Division by zero" error

I want to return data from yesterday and 8 days ago.
To do this I use the following line in my query:
WHERE (o.status_date::date = now()::date - INTERVAL '8 days')
OR (o.status_date::date = now()::date - INTERVAL '1 day')
However, this returns a "Division by zero" error. When I use only one of the two, so for example:
WHERE (o.status_date::date = now()::date - INTERVAL '8 days')
I get no error...
I don't understand where the error comes from, or perhaps I'm making a very straightforward mistake. Any help is appreciated!
Edited, these are the calculations done in my query:
SUM(CASE WHEN o.status_id = '12' THEN 1 ELSE 0 END) AS failed_63,
SUM(CASE WHEN o.status_id IN ('6','11','12','14','22','24') THEN 1 ELSE 0 END) AS total_orders,
ROUND(
(SUM(CASE WHEN o.status_id = '12' THEN 1 ELSE 0 END) * 100)::numeric /
(SUM(CASE WHEN o.status_id IN ('11','12','14','22','24') THEN 1 ELSE 0 END)), 2) AS perc_fail,
COUNT(DISTINCT i.order_id) AS order_issues,
ROUND(
(COUNT(DISTINCT i.order_id) * 100)::numeric / (SUM(CASE WHEN o.status_id IN ('11','12','14','22','24') THEN 1 ELSE 0 END)), 2) AS issue_rate,
SUM(CASE WHEN o.status_id = '6' THEN 1 ELSE 0 END) AS overdue_53,
ROUND(
(SUM(CASE WHEN o.status_id = '6' THEN 1 ELSE 0 END) * 100)::numeric /
(SUM(CASE WHEN o.status_id IN ('6','11','12','14','22','24') THEN 1 ELSE 0 END)), 2) AS perc_overdue,
ROUND(
(AVG(dop.vendor_confirmation_time)::numeric / 60), 2) AS avg_v_confirmation_time,
CASE
WHEN (AVG(dop.vendor_confirmation_time)::numeric / 60) < 3 THEN 'good'
WHEN (AVG(dop.vendor_confirmation_time)::numeric / 60) IS NULL THEN 'n/a'
ELSE 'bad'
END AS vendor_response
You have several cases in your query where your divisor might be 0, as in:
SUM(CASE WHEN o.status_id IN ('6','11','12','14','22','24') THEN 1 ELSE 0 END)
The best way to solve this is to use a sub-query to calculate all the sums, which are repeated anyway, and then do the division and rounding in the main query, where the divisor is not 0:
SELECT
sum12 AS failed_63,
sum6 + sum12 + sum11_24 AS total_orders,
CASE WHEN sum12 + summ11_24 > 0 THEN round(sum12 * 100. / (sum11_24 + sum 12), 2)
ELSE NULL END AS perc_fail,
order_issues,
CASE WHEN sum12 + summ11_24 > 0 THEN round(order_issues * 100. / (sum12 + sum11_24), 2)
ELSE NULL END AS issue_rate,
sum6 AS overdue_53,
CASE WHEN sum6 + sum12 + sum11_24 > 0 THEN round(sum6 / (sum6 + sum12 + sum11_24), 2)
ELSE NULL END AS perc_overdue,
round(avg_v_confirmation_time, 2) AS avg_v_confirmation_time,
CASE
WHEN (avg_v_confirmation_time) < 3 THEN 'good'
WHEN (avg_v_confirmation_time) IS NULL THEN 'n/a'
ELSE 'bad'
END AS vendor_response
FROM (
SELECT
sum(CASE WHEN o.status_id = '6' THEN 1 ELSE 0 END) AS sum6,
sum(CASE WHEN o.status_id = '12' THEN 1 ELSE 0 END) AS sum12,
sum(CASE WHEN o.status_id IN ('11','14','22','24') THEN 1 ELSE 0 END) AS sum11_24,
count(DISTINCT i.order_id) AS order_issues,
avg(dop.vendor_confirmation_time::numeric / 60) AS avg_v_confirmation_time
FROM o, i, dop
WHERE ... ) sub
In this case I set all columns where the divisor would be 0 to NULL; change as appropriate.
For future questions:
List your PostgreSQL version
Post the entire query with table qualifiers for all columns
Preferably, post the table structure
I still don't know why my first line didn't work, but I've now found a work-around by using the following:
WHERE o.status_date::date BETWEEN CURRENT_DATE - INTERVAL '8 days' AND CURRENT_DATE - INTERVAL '1 day'
AND o.status_date::date NOT BETWEEN CURRENT_DATE - INTERVAL '7 days' AND CURRENT_DATE - INTERVAL '2 days'

SQL Switch/Case in SQL Server 2008 R2

Here is my test T-SQL.
DECLARE #TestVal INT
SET #TestVal = 1
SELECT
CASE #TestVal
WHEN (1 | 2 | 6) THEN 'First' // I would like to check 1 or 2 or 6.
WHEN 3 THEN 'Second'
WHEN 4 THEN 'Third'
ELSE 'Other'
END
The current result is 'Other'.
I would like to get the result as 'First'. How can I use (OR statement) in my T-SQL.
Best regards
Use the condition form of case:
SELECT (CASE WHEN #TestVal IN (1, 2, 6) THEN 'First'
WHEN #TestVal = 3 THEN 'Second'
WHEN #TestVal = 4 THEN 'Third'
ELSE 'Other'
END)
Try this instead:
SELECT
CASE WHEN #TestVal IN (1, 2, 6) THEN 'First'
WHEN #TestVal = 3 THEN 'Second'
WHEN #TestVal = 4 THEN 'Third'
ELSE 'Other'
END
Above answers are correct also you can use OR like this:
DECLARE #TestVal INT
SET #TestVal = 2
SELECT (CASE WHEN (#TestVal = 1 OR #TestVal=2 OR #TestVal=6) THEN 'First'
WHEN #TestVal = 3 THEN 'Second'
WHEN #TestVal = 4 THEN 'Third'
ELSE 'Other'
END)

T-SQL CASE (SQL Server 2000)

I have a T-SQL query that I need to total out the counts for the CASE statements.
I tried to add a UNION but I am getting an error:
All queries in an SQL statement containing a UNION operator must have
an equal number of expressions in their target lists.
Any ideas? Thanks.
Query:
SELECT
CustomerID, Name, DueDate,
CASE WHEN DATEDIFF(Month, PaymentDate, DueDate) >= 1
THEN PaymentAmount ELSE 0
END AS [Early],
CASE WHEN DATEDIFF(Month, PaymentDate, DueDate) >=0
THEN PaymentAmount ELSE 0
END AS [On Time],
CASE WHEN DATEDIFF(Month, PaymentDate, DueDate) = -1
THEN PaymentAmount ELSE 0
END AS [Late]
FROM
Customers
WHERE
DATEDIFF(MONTH, PaymentDate,DueDate), GetDate()) = 1
AND PaymentAmount= DuesAmount
UNION
SELECT
'-Total', '', CustomerID, Name, DueDate,
SUM(CASE WHEN DATEDIFF(Month, PaymentDate, DueDate) >= 1
THEN PaymentAmount ELSE 0 END) AS [Early],
SUM(CASE WHEN DATEDIFF(Month, PaymentDate, DueDate) >= 0
THEN PaymentAmount ELSE 0 END) AS [On Time],
SUM(CASE WHEN DATEDIFF(Month, PaymentDate, DueDate) = -1
THEN PaymentAmount ELSE 0 END) AS [Late]
FROM
Customers
WHERE
DATEDIFF(MONTH, PaymentDate,DueDate), GetDate()) = 1
AND PaymentAmount = DuesAmount
The error says, "All queries in a SQL statement containing a UNION operator must have an equal number of expressions in their target lists." What this means is that each SELECT must return the same number of expressions.
In the code sample you gave us, the first SELECT statement returns 6 expressions, while the second one returns 8:
SELECT CustomerID, -- 1
Name, -- 2
DueDate, -- 3
CASE ... END AS [Early], -- 4
CASE ... END AS [On Time], -- 5
CASE ... END AS [Late] -- 6
...
UNION
SELECT '-Total', -- 1
'', -- 2
CustomerID, -- 3
Name, -- 4
DueDate, -- 5
SUM(CASE ... END) AS [Early], -- 6
SUM(CASE ... END) AS [On Time], -- 7
SUM(CASE ... END) AS [Late] -- 8
...
See how the first SELECT returns 6 expressions, but the second returns 8? In a UNION, all the SELECT statements must return the same number of expressions.
You can return NULL in the first query for columns that don't have a match in the second, if necessary. For example:
SELECT NULL as [RowType], -- 1
NULL as [Padding], -- 2
CustomerID, -- 3
Name, -- 4
DueDate, -- 5
CASE ... END AS [Early], -- 6
CASE ... END AS [On Time], -- 7
CASE ... END AS [Late] -- 8
...
UNION
SELECT '-Total', -- 1
'', -- 2
CustomerID, -- 3
Name, -- 4
DueDate, -- 5
SUM(CASE ... END) AS [Early], -- 6
SUM(CASE ... END) AS [On Time], -- 7
SUM(CASE ... END) AS [Late] -- 8
...
Also, note that you don't have a comma after the DueDate column.

How to average 3 values in Sql Server?

I have three variables :-
#ScoreA DECIMAL(10,7)
#ScoreB DECIMAL(10,7)
#ScoreC DECIMAL(10,7)
#FinalScore DECIMAL(10, 7)
I wish to get the average of the three scores. BUT 1, 2 or all 3 values might be zero.
Eg. scenarios:
A = 1.4, B=3.5, C=5.0; FinalScore = 3.3
A = 0.0, B=0.0, C=0.0; FinalScore = 0.0
A = 1.1, B=0.0, C=0.0; FinalScore = 1.1
A = 0.0, B=2.0, C=4.8; FinalScore = 3.4
Cheers!
IF #A > 0 OR #B > 0 OR #C > 0
SELECT ((#A + #B + #C) /
(0 +
CASE WHEN #A = 0 THEN 0 ELSE 1 END +
CASE WHEN #B = 0 THEN 0 ELSE 1 END +
CASE WHEN #C = 0 THEN 0 ELSE 1 END ))
ELSE
SELECT 0.0
EDIT
Modified query to now handle divide by zero scenario's.
EDIT2
Here is "the trick with the AVG(..) function" :) with Common Table Expression
WITH T(I) AS (SELECT #A UNION SELECT #B UNION SELECT #C)
SELECT AVG(I) FROM T
WHERE I > 0
SELECT ((#A + #B + #C) /
(CASE WHEN (#A = 0.0 AND #B = 0.0 AND #C = 0.0) THEN 1 ELSE 0 END
+ CASE WHEN #A = 0 THEN 0 ELSE 1 END
+ CASE WHEN #B = 0 THEN 0 ELSE 1 END
+ CASE WHEN #C = 0 THEN 0 ELSE 1 END
)
)
For me this is easier to read and understand:
DECLARE
#ScoreA DECIMAL(10,7),
#ScoreB DECIMAL(10,7),
#ScoreC DECIMAL(10,7),
#FinalScore DECIMAL(10, 7)
SET #ScoreA = 1.4
SET #ScoreB = 3.5
SET #ScoreC = 5.0
DECLARE
#AVG TABLE (value DECIMAL(10,7))
INSERT INTO #AVG
SELECT #ScoreA WHERE #ScoreA > 0
UNION
SELECT #ScoreB WHERE #ScoreB > 0
UNION
SELECT #ScoreC WHERE #ScoreC > 0
SELECT COALESCE(AVG(value), 0) FROM #AVG