Combining several queries into 1 new query - sql-server-2008-express

I have a table that consists of all of our agency records. I have several queries set up that count something specific about these records and each query groups them all by date. What I am trying to figure out is how I can combine these queries into one new query. Right now, I run each one, put them into Excel and then do a vlookup and combine them into one. Here are just two of my queries.
Query #1:
select
LocationStateAbr,
count(LocationStateAbr) as "Total Agencies"
from
[PROD_Agency].[dbo].[AgAgency]
where
StatusId = ' '
and BusinessId in ('b', 'C')
and TypeId in ('A', 'C', 'F', 'I', 'X')
group by
LocationStateAbr
order by
LocationStateAbr ASC
Query #2:
select
LocationStateAbr,
count(LocationStateAbr) as "New Agencies"
from
[PROD_Agency].[dbo].[AgAgency]
where
year(AppointedDt) = 2018
and StatusId = ' '
and BusinessId in ('b', 'C')
and TypeId in ('A', 'C', 'F', 'I', 'X')
group by
LocationStateAbr
order by
LocationStateAbr ASC
Any suggestions? Thank you!

You can combine the two queries into one using CASE. In your case it would be something like this:
select
LocationStateAbr,
count(case when StatusId = ' '
and BusinessId in ('b', 'C')
and TypeId in ('A', 'C', 'F', 'I', 'X') then 1 else null end) as "Total Agencies",
count(case when year(AppointedDt) = 2018
and StatusId = ' '
and BusinessId in ('b', 'C')
and TypeId in ('A', 'C', 'F', 'I', 'X') the 1 else null end) as "New Agencies"
FROM
[PROD_Agency].[dbo].[AgAgency]
group by
LocationStateAbr
order by
LocationStateAbr ASC

Related

Return single value when checking table rows values

Im trying to return a single value from a table with a lot of rows if a condition is met.
For example, I have a table (ID (pk), CODE (pk), DESCRIPTION) which has a lot of rows. How can I return in a single row if..
SELECT CASE
WHEN CODE IN ('1', '2') THEN '100'
WHEN CODE IN ('2', '3') THEN '200'
WHEN CODE IN ('5', '7') THEN '300'
END AS ASDASD
FROM TABLE
WHERE ID = 1;
The problem is that CODE must check for both and not just one of them. The code as it is will return if for example that ID has got the code '2'.
ASDASD
NULL
'200'
And I want to return just '200' because that ID has got code '2' and '3'.
Assuming codes are not duplicated for a particular id:
SELECT ID,
(CASE WHEN SUM(CASE WHEN CODE IN ('1', '2') THEN 1 ELSE 0 END) = 2
THEN '100'
WHEN SUM(CASE WHEN CODE IN ('2', '3') THEN 1 ELSE 0 END) = 2
THEN '200'
WHEN SUM(CASE WHEN CODE IN ('5', '7') THEN 1 ELSE 0 END) = 2
THEN '300'
END) AS ASDASD
FROM TABLE
WHERE ID = 1
GROUP BY ID;
I added ID to the SELECT, just because this might be useful for multiple ids.
You could try and use condition aggregation, as follows :
SELECT CASE
WHEN MAX(DECODE(code, '1', 1)) = 1 AND MAX(DECODE(code, '2', 1)) = 1
THEN '100'
WHEN MAX(DECODE(code, '2', 1)) = 1 AND MAX(DECODE(code, '3', 1)) = 1
THEN '200'
WHEN MAX(DECODE(code, '5', 1)) = 1 AND MAX(DECODE(code, '7', 1)) = 1
THEN '300'
END AS asdasd
FROM TABLE
WHERE ID = 1;
DECODE() is a handy Oracle function that compares an expression (code) to a series of values and returns results accordingly. Basically, condition MAX(DECODE(code, '1', 1)) = 1 ensures that at least one row has code = '1'.
PS : are you really storing numbers as strings ? If code is a number datatype, please remove the single quotes in the above query.
You need to check the number returned by a query like this:
SELECT COUNT(DISTINCT CODE) FROM TABLE WHERE ID = 1 AND CODE IN ('1', '2')
If this number is 2 then ID = 1 has both CODE values '1' and '2'.
SELECT
CASE
WHEN (SELECT COUNT(DISTINCT CODE) FROM TABLE WHERE ID = 1 AND CODE IN ('1', '2')) = 2 THEN '100'
WHEN (SELECT COUNT(DISTINCT CODE) FROM TABLE WHERE ID = 1 AND CODE IN ('2', '3')) = 2 THEN '200'
WHEN (SELECT COUNT(DISTINCT CODE) FROM TABLE WHERE ID = 1 AND CODE IN ('5', '7')) = 2 THEN '300'
END AS ASDASD
FROM TABLE

using COUNT (CASE WHEN....) vs CASE WHEN = ...THEN COUNT . I get different results, can someone kindly explain why?

When i use method 1: ' COUNT (Case WHEN..) ' method it produces the output that I want, but when i use the 2nd method ' CASE WHEN .. COUNT ' method, i get a diagonal matrix of sorts which is not what I am looking for.
My steps are :
i) Created a dummy table
INSERT INTO job (jobid, jobname, [priority])
VALUES ('something', '1', 1),
('something', '2', 2),
('something', '3', 3),
('something', '4', 4),
('something', '5', 5),
('something', '6', 1),
('something', '7', 1),
('something', '8', 3),
('something', '9', 3),
('something', '10', 2);
ii) method 1 : COUNT (CASE WHEN....)
SELECT
COUNT(CASE WHEN [Priority] = 1 THEN 1 ELSE NULL END ) as Priority1,
COUNT(CASE WHEN [Priority] = 2 THEN 1 ELSE NULL END )as Priority2,
COUNT(CASE WHEN [Priority] = 3 THEN 1 ELSE NULL END )as Priority3
FROM job
Result :
Priority1 Priority2 Priority3
3 2 3
iii) method 2 : CASE WHEN .... COUNT
SELECT
CASE WHEN [Priority] = 1 THEN COUNT(*) END as Priority1,
CASE WHEN [Priority] = 2 THEN COUNT(*) END as Priority2,
CASE WHEN [Priority] = 3 THEN COUNT(*) END as Priority3
FROM job
GROUP BY [Priority]
Result :
Priority1 Priority2 Priority3
3 NULL NULL
NULL 2 NULL
NULL NULL 3
NULL NULL NULL
NULL NULL NULL
Method 1 gives me the right result, but method 2's output suprised me... i was expecting the same result as method 1!
Method 1:
The aggregate function COUNT is applied at the table level and COUNT ignored and consumed all the NULL values (cases where [Priority] is other than 1, 2 or 3). So, at the end you got only 1 row.
Method 2:
The aggregate function COUNT is applied to each row of the table. So, the result contains equal number of rows as the number of unique [Priority] values in the table. And result contains some NULL because the case condition didn't satisfied in those cases and COUNT return NULL.
You have a group by in the second method, so you are going to get one row per value in Priority.
So you sort of want:
SELECT CASE WHEN [Priority] = 1 THEN COUNT(*) END as Priority1,
CASE WHEN [Priority] = 2 THEN COUNT(*) END as Priority2,
CASE WHEN [Priority] = 3 THEN COUNT(*) END as Priority3
FROM job;
But this won't work. Because [Priority] is not aggregated.
Hmmm, you are basically back to your first method, where the condition is in the argument to the aggregation function Your expectation is wrong. Use the first method (although I personally prefer using SUM() to COUNT()).

How to assign multiple values in CASE statement?

I need to assign two values to my select based on a CASE statement. In pseudo:
select
userid
, case
when name in ('A', 'B') then 'Apple'
when name in ('C', 'D') then 'Pear'
end as snack
from
table
;
I am assigning a value for snack. But lets say I also want to assign a value for another variable, drink based on the same conditions. One way would be to repeat the above:
select
userid
, case
when name in ('A', 'B') then 'Apple'
when name in ('C', 'D') then 'Pear'
end as snack
, case
when name in ('A', 'B') then 'Milk'
when name in ('C', 'D') then 'Cola'
end as drink
from
table
;
However, if I have to assign more values based on the same conditions, say food, drink, room, etc. this code becomes hard to maintain.
Is there a better way of doing this? Can I put this in a SQL function, like you would normally do in another (scripting) language and if so, could you please explain how?
When doing things like this I tend to use a join with a table valued constructor:
SELECT t.UserID,
s.Snack,
s.Drink
FROM Table AS T
LEFT JOIN
(VALUES
(1, 'Apple', 'Milk'),
(2, 'Pear', 'Cola')
) AS s (Condition, Snack, Drink)
ON s.Condition = CASE
WHEN t.name IN ('A', 'B') THEN 1
WHEN t.name IN ('C', 'D') THEN 2
END;
I find this to be the most flexible if I need to add further conditions, or columns.
Or more verbose, but also more flexible:
SELECT t.UserID,
s.Snack,
s.Drink
FROM Table AS T
LEFT JOIN
(VALUES
('A', 'Apple', 'Milk'),
('B', 'Apple', 'Milk'),
('C', 'Pear', 'Cola'),
('D', 'Pear', 'Cola')
) AS s (Name, Snack, Drink)
ON s.Name= t.name;
Functions destroy performance. But you could use a common-table-expression(cte):
with cte as
(
Select IsNameInList1 = case when name in ('A', 'B')
then 1 else 0 end,
IsNameInList2 = case when name in ('C', 'D')
then 1 else 0 end,
t.*
from table
)
select
userid
, case when IsNameInList1=1 then 'Apple'
when IsNameInList2=1 then 'Pear'
end as snack
, case when IsNameInList1=1 then 'Milk'
when IsNameInList2=1 then 'Cola'
end as drink
from
cte
;
On this way you have only one place to maintain.
If query performance doesn't matter and you want to use a scalar valued function like this:
CREATE FUNCTION [dbo].[IsNameInList1]
(
#name varchar(100)
)
RETURNS bit
AS
BEGIN
DECLARE #isNameInList bit
BEGIN
SET #isNameInList =
CASE WHEN #name in ('A', 'B')
THEN 1
ELSE 0
END
END
RETURN #isNameInList
END
Then you can use it in your query in this way:
select
userid
, case when dbo.IsNameInList1(name) = 1 then 'Apple'
when dbo.IsNameInList2(name) = 1 then 'Pear'
end as snack
from
table
;
But a more efficient approach would be to use a real table to store them.
Hope this will help you
SELECT userid
,(CASE flag WHEN 1 THEN 'Apple' WHEN 2 THEN 'Pear' WHEN 3 THEN '..etc' END ) as snack
,(CASE flag WHEN 1 THEN 'Milk' WHEN 2 THEN 'Cola' WHEN 3 THEN '..etc' END ) as drink
FROM (
SELECT userid
,( CASE WHEN name IN ('A', 'B') THEN 1
WHEN name IN ('C', 'D') THEN 2
WHEN name IN ('X', 'Y') THEN 3
ELSE 0 END ) AS flag
FROM table ) t
As Ganesh suggested in a comment, I recommend creating a mapping table for this and just do lookups. Much easier to interpet, maintain, and scale - all with better performance.

Determining what indexes should be created in DB2 to optimize the performance of a particular query

Let's say I have the query below and it runs for an unacceptably lengthy amount of time... how do I determine from the query what indexes should be created to optimize it?
Does creating indexes from the fields in the SELECT clause help?
Or should I only create indexes based on the fields in the WHERE conditions?
Considering I also have conditions in the CASE clauses, will creating indexes for those fields also help?
SELECT A.ALPHA,
C.BETA,
A.KAPPA AS DELTA,
A.ECHO,
B.FOXTROT,
D.GAMMA,
CASE WHEN (D.THETA IN ('B', '3', '4', 'F', 'D', 'H') OR (D.THETA = 'E' AND D.EPSILON <> '9'))
THEN D.MU
WHEN D.THETA = 'E' AND D.EPSILON = '9'
THEN D.IOTA
ELSE D.PHI END AS PHI,
D.CHI,
CASE WHEN D.THETA LIKE '1%'
THEN '1'
WHEN D.THETA LIKE 'P%'
THEN '2'
WHEN (THETA IN ('B', '3', '4') OR (THETA = 'E' AND PSI <> 'S'))
THEN '3'
WHEN (THETA in ('F', 'D', 'H') OR (THETA = 'E' AND PSI = 'S'))
THEN '4'
END AS OMEGA,
CASE WHEN B.FOXTROT IN (SELECT DISTINCT FOXTROT FROM TAPPLE)
THEN 'Y'
ELSE 'N' END AS ZETA,
CASE WHEN D.THETA LIKE 'E%' AND D.PSI <> 'S'
THEN D.TAU
WHEN D.THETA LIKE 'B%'
THEN D.TAU
WHEN D.THETA LIKE '3%'
THEN DATE(D.SIGMA)
WHEN D.THETA LIKE '4%'
THEN DATE(D.SIGMA)
ELSE NULL END AS RHO
FROM TORANGE A,
TLIME B,
(SELECT FOXTROT,BETA FROM TLIME, TLEMON WHERE OMICRON='L' AND ECHO = BETA AND LAMBDA = 'M') C,
TGRAPE D
WHERE A.ECHO = B.ECHO
AND B.FOXTROT = C.FOXTROT
AND B.OMICRON = 'O'
AND B.FOXTROT = D.FOXTROT
AND D.THETA IN ('1', 'B', '3', '4', 'E', 'F', 'D', 'H')
;
If you are using DB2 for LUW, you can feed your actual query to the DB2 Design Advisor, which may suggest indexes and other approaches to improving the expected query performance.

SQL return multiple values from CASE statement

How do I rewrite this SQL statement to do what I need?
SELECT * FROM TABLE
WHERE COLUMN_NAME_1 IN (CASE
WHEN COLUMN_NAME_2 = 'X' THEN 'A'
WHEN COLUMN_NAME_2 = 'Y' THEN 'B', 'C' END)
Obviously I can't return multiple values from a CASE clause... so how else could I write this? I am pretty sure I am slow today because this seems so easy ....
SELECT * FROM Table WHERE
(COLUMN_NAME_2 = 'X' AND COLUMN_NAME_1 = 'A') OR
(COLUMN_NAME_2 = 'Y' AND COLUMN_NAME_1 IN ('B', 'C'))
or
SELECT * FROM Table WHERE COLUMN_NAME_2 = 'X' AND COLUMN_NAME_1 = 'A'
UNION ALL
SELECT * FROM Table WHERE COLUMN_NAME_2 = 'Y' AND COLUMN_NAME_1 IN ('B', 'C')
This presumes that you only want results with X or Y in COLUMN_NAME_2. If you want other rows it's not possible to tell which ones from your original SQL.