I have a query which returns this data back from lets say DefaultersTable
Select CustomerID, RoleID FROM DefaultersTable Where DefaulterValue = 1
CustomerID, RoleID
10034 34
15481 37
Now I have got another Table "DefaultersDetails" which have individual monthly values of them,
so I do
Select * from DefaultersDetails Where CustomerID = 10034 AND RoleID = 34.
and get the data
CustomerID, RoleID, ValueForJan, ValueForFeb, ValueforMar
10034 34 45 0 32
Please note that I got this Entry in the first case only because one of the Value was 0.
Now How Can I get both the data in single Query, I want something like this
CustomerID, RoleID, ZeroValueForMonth
10034 34 ValueForFeb
15481 37 ValueForJan
I guess it can be done via temprory Tables but I am not sure how to do this
You can use COALESCE function. Try this :
SELECT d.CustomerID, d.RoleID,
COALESCE(detail.JAN,detail.FEB,detail.MAR) AS ZeroValueForMonth
FROM DefaultersTable d
INNER JOIN
(
SELECT CustomerID, RoleID,
(CASE WHEN ValueForJan <> 0 THEN NULL ELSE 'ValueForJan' END) JAN,
(CASE WHEN ValueForFeb <> 0 THEN NULL ELSE 'ValueForFeb' END) FEB,
(CASE WHEN ValueForMar <> 0 THEN NULL ELSE 'ValueForMar' END) MAR
FROM Defaultersdetail
) AS detail
ON detail.CustomerID = d.CustomerID AND detail.RoleID = d.RoleId
where d.DefaulterValue = 1
You can add other month like MAY, JUN etc on subquery like this :
(CASE WHEN ValueForApr <> 0 THEN NULL ELSE 'ValueForApr' END) APR
Related
I would like the following pivot query to show value 0 instead of null,
SELECT
pi.employeeId,
pi.Id,
MAX(CASE
WHEN pi.category = 'Repayment' THEN pi.value
WHEN isnull(pi.category) = 1 then 0
-- ELSE 0
END) as 'Repayment',
MAX(CASE
WHEN pi.category = 'Salary' THEN pi.value
ELSE 0
END) as 'Salary',
MAX(CASE
WHEN pi.category = 'Allowance' THEN pi.value
ELSE 0
END) as 'Allowance'
FROM
payData pi
GROUP BY pi.employeeId , pi.Id ;
Output for the above is,
employeeId Id Repayment Salary Allowance
121 2 2000 15000 1000
122 2 null 20000 2000
Employee id 122 does not have a Repayment value so the desired output is,
employeeId Id Repayment Salary Allowance
121 2 2000 15000 1000
122 2 0 20000 2000
dbfiddle
I don't see the need for the second branch of the repayment case. If you want 0 when the category is not available, just else 0:
SELECT
employeeId,
Id,
MAX(CASE WHEN category = 'Repayment' THEN value ELSE 0 END) as Repayment,
MAX(CASE WHEN category = 'Salary' THEN value ELSE 0 END) as Salary,
MAX(CASE WHEN category = 'Allowance' THEN value ELSE 0 END) as Allowance
FROM payData pi
GROUP BY employeeId, Id;
Notes:
Don't use single quotes for identifiers! They should be used for literal strings only, as specified in ANSI SQL and supported in all databases.
You have a mono-table query, so prefixing all column names is not mandatory
I have a table which traces the users records I want to know which are the complete and process users's records based on their status
Here is the sql query
SELECT users.UserID,users.UserName,users.FirstName,users.LastName,users.Email,
CASE WHEN inword.inword_status = '3' THEN count(*) END As 'Process' ,
CASE WHEN inword.inword_status = '4' THEN count(*) END AS 'Complete'
FROM tbl_user users
INNER JOIN tbl_inword inword on users.UserID=inword.UserID
Where inword.Status=1 and users.Status=1 and
inword.CreatedDate BETWEEN '2020-10-01' and '2020-10-31' and inword.inword_status in (3)
group by users.UserID
Here is Query Output
My Expected result is
UserID Name Total Process Complete
1 Umair 1 1 0
1 Basit 20 20 0
1 Zaidi 34 32 2
Any Help would be Appreciated
You're not doing your conditional aggregation correctly, you should use something like:
COUNT(CASE WHEN inword.inword_status = '3' THEN inword.UserId END) As 'Process' ,
COUNT(CASE WHEN inword.inword_status = '4' THEN inword.UserId END) AS 'Complete'
Or you can take advantage of MySQL treating booleans as 1 or 0 in a numeric context and simplify to:
SUM(inword.inword_status = '3') As 'Process' ,
SUM(inword.inword_status = '4') AS 'Complete'
Locked. There are disputes about this question’s content being resolved at this time. It is not currently accepting new answers or interactions.
I am new to SQL and would like to know how to approach writing a query for this question.
Lets say we have these fields:
date_created date_unsubscribed subscriberid
How to write a SQL query that lists, by month, how many people subscribed to the list, unsubscribed from the list, and how many net subscribers there were (new subscribers minus unsubscribers).
All in a single query...
Here's one option using conditional aggregation and union all:
select month(dt),
count(case when subscribe = 1 then 1 end) subscribecount,
count(case when subscribe = -1 then 1 end) unsubscribecountt,
sum(subscribe) overallcount
from (
select date_created as dt, 1 as subscribe
from yourtable
union all
select date_unsubscribed, -1
from yourtable
where date_unsubscribed is not null
) t
group by month(dt)
The subquery creates a list of dates with a flag for subscribe or unsubscribe. Then you can use count with case to determine the appropriate number of subscribers/unsubscribers.
SQL Fiddle Demo
You could write a sum(case) (a sum with conditions) to aggregate - assuming the date_created column is never null. For instance:
ORACLE:
SELECT
TO_CHAR(DATE_CREATED,'MM-YYYY') CREATE_MONTH
,SUM(CASE WHEN date_unsubscribed is not null then 1 else 0 end) unsubscribed
,SUM(CASE WHEN date_unsubscribed is null then 1 else 0 end) subscribed
,COUNT(SUBSCRIBER_ID)
FROM
--YOURTABLENAME
--WHERE
--WHATEVER OTHER CONDITIONS YOU HAVE APPLY
GROUP BY TO_CHAR(DATE_CREATED,'MM-YYYY')
MYSQL:
SELECT
DATE_FORMAT(DATE_CREATED,'%m-%Y') CREATE_MONTH
,SUM(CASE WHEN date_unsubscribed is not null then 1 else 0 end) unsubscribed
,SUM(CASE WHEN date_unsubscribed is null then 1 else 0 end) subscribed
,COUNT(SUBSCRIBER_ID)
FROM
--YOURTABLENAME
--WHERE
--WHATEVER OTHER CONDITIONS YOU HAVE APPLY
GROUP BY DATE_FORMAT(DATE_CREATED,'%m-%Y')
Oracle solution
Here is a query using the PIVOT operator, which was created exactly for this kind of work, and ROLLUP to get the net number. This is just for illustration; I assume the year is a user or application input (bind variable :year, set to 2015 for the output), and I show the summary for January through June.
with
test_data ( date_created, date_unsubscribed, subscriber_id ) as (
select date '2015-05-10', null , 330053448 from dual union all
select date '2015-04-28', null , 330053457 from dual union all
select date '2015-05-10', null , 330053466 from dual union all
select date '2015-04-28', null , 220053475 from dual union all
select date '2015-04-28', date '2015-05-10', 330053484 from dual
),
prep ( type, val, mth ) as (
select 'Subscribed' , 1, extract(month from date_created) from test_data
where extract(year from date_created) = :year
union all
select 'Unsubscribed', -1, extract(month from date_unsubscribed) from test_data
where extract(year from date_unsubscribed) = :year
)
select nvl(type, 'Net Subscr') as description,
nvl(sum(jan), 0) as jan, nvl(sum(feb), 0) as feb, nvl(sum(mar), 0) as mar,
nvl(sum(apr), 0) as apr, nvl(sum(may), 0) as may, nvl(sum(jun), 0) as jun
from prep
pivot (
sum(val)
for mth in (1 as jan, 2 as feb, 3 as mar, 4 as apr, 5 as may, 6 as jun)
)
group by rollup(type)
order by case type when 'Subscribed' then 1 when 'Unsubscribed' then 2 else 3 end
;
DESCRIPTION JAN FEB MAR APR MAY JUN
------------ ---------- ---------- ---------- ---------- ---------- ----------
Subscribed 0 0 0 3 2 0
Unsubscribed 0 0 0 0 -1 0
Net Subscr 0 0 0 3 1 0
3 rows selected.
I have the following database structure:
FieldID|Year|Value
a|2011|sugar
a|2012|salt
a|2013|pepper
b|2011|pepper
b|2012|pepper
b|2013|pepper
c|2011|sugar
c|2012|salt
c|2013|salt
now I would like to run a query that counts the number of fields for every item in the particular year looking something like this:
value|2011|2012|2013
sugar|2|0|0
salt |0|2|1
pepper|1|1|2
I used multiple tables for every year before. However the distinct values for 2011,2012 and 2013 might be different (e.g. sugar would only be present in 2011)
For individual years I used:
SELECT `Value`, COUNT( `FieldID` ) FROM `Table` WHERE `Year`=2011 GROUP BY `Value`
A1ex07's answer is fine. However, in MySQL, I prefer this formulation:
SELECT Value,
sum(`Year` = 2011) AS cnt2011,
sum(`Year` = 2012) AS cnt2012,
sum(`Year` = 2013) AS cnt2013
FROM t
GROUP BY value;
The use of count( . . . ) produces the correct answer, but only because the else clause is missing. The default value is NULL and that doesn't get counted. To me, this is a construct that is prone to error.
If you want the above in standard SQL, I go for:
SELECT Value,
sum(case when `Year` = 2011 then 1 else 0 end) AS cnt2011,
sum(case when `Year` = 2012 then 1 else 0 end) AS cnt2012,
sum(case when `Year` = 2013 then 1 else 0 end) AS cnt2013
FROM t
GROUP BY value;
You can do pivoting :
SELECT `Value`,
COUNT(CASE WHEN `Year` = 2011 THEN FieldID END) AS cnt2011,
COUNT(CASE WHEN `Year` = 2012 THEN FieldID END) AS cnt2012,
COUNT(CASE WHEN `Year` = 2013 THEN FieldID END) AS cnt2013
FROM `Table`
GROUP BY `Value`
It is called Pivot Table, achieve with a chain of CASE statements which apply a 1 or 0 for each condition, then SUM() up the ones and zeros to retrieve a count.
SELECT
Value,
SUM(CASE WHEN Year = 2011 THEN 1 ELSE 0 END) AS 2012,
SUM(CASE WHEN Year = 2012 THEN 1 ELSE 0 END) AS 2012,
SUM(CASE WHEN Year = 2013 THEN 1 ELSE 0 END) AS 2013
FROM Table
GROUP BY Value
Have this query:
SELECT
count(*) as Total,
SUM(CASE WHEN gender = 1 then 1 ELSE 0 END) Male,
SUM(CASE WHEN gender = 2 then 1 ELSE 0 END) Female,
SUM(CASE WHEN gender = 0 then 1 ELSE 0 END) Unknown,
CASE
WHEN age>2 AND age<15 THEN '2-15'
WHEN age>18 AND age<25 THEN '18-25'
END AS var
FROM
persons
WHERE
1=1
AND `date` > '2012-01-10'
AND `date` < '2013-01-07'
GROUP BY
CASE
WHEN age>2 AND age<15 THEN '2-15'
WHEN age>18 AND age<25 THEN '18-25'
END
And is resulting this:
Total Male Female Unknown var
29 17 12 0 NULL
7 0 7 0 18-25
3 0 3 0 2-15
1st question: Why is this resulting that NULL ? What could be done to only show results with values?
2nd question: mysql is ordering my var column with 18-25 before 2-15, migth be because of number 1 cames first then number 2. But the point is order that as numbers, and 2 came first then 18.
Cheers :)
1st answer:
It is NULL because it does not satisfy any of your CASE conditions for the age. Adding a clause to the WHERE like this should do it:
WHERE (age > 2 AND age < 15) OR (age > 18 AND age < 25)
2nd answer:
You are correct, it is ordering them by strings (because that is what they are). Just change the direction of the sort by doing ORDER ASC or ORDER DESC
This is because all CASE expression has an (implied, default) ELSE NULL part. SO, any age value that is not caught by either the age>2 AND age<15or the age>18 AND age<25 condition, results in the NULL value being grouped.
Solution is to add one more restriction at the WHERE clause:
WHERE 1=1
AND `date` > '2012-01-10' AND `date` < '2013-01-07'
AND ( (age>2 AND age<15) OR (age>18 AND age<25) ) -- this
For the second question, you can use a function on age to avoid the comparison being made on the var (which is a string):
ORDER BY MIN(age)
or just:
ORDER BY age
None of the above is by the SQL standard but it works in MySQL, under the default non-ANSI settings. If you want to be 100% by the book, you can change slightly the var:
SELECT count(*) as Total,
SUM(CASE WHEN gender = 1 then 1 ELSE 0 END) Male,
SUM(CASE WHEN gender = 2 then 1 ELSE 0 END) Female,
SUM(CASE WHEN gender = 0 then 1 ELSE 0 END) Unknown,
CASE
WHEN age>2 AND age<15 THEN '02-15' -- this was changed
WHEN age>18 AND age<25 THEN '18-25'
END AS var
FROM persons
WHERE 1=1
AND `date` > '2012-01-10' AND `date` < '2013-01-07'
AND ( (age>2 AND age<15) OR (age>18 AND age<25) )
GROUP BY
CASE
WHEN age>2 AND age<15 THEN '02-15'
WHEN age>18 AND age<25 THEN '18-25'
END
ORDER BY var ;
you are getting NULL
because it doesnt meet your CASE
CASE
WHEN age>2 AND age<15 THEN '2-15' // U HAVE BETWEEN 2-15
WHEN age>18 AND age<25 THEN '18-25' // u have between 18-25
// but u dont have between 15-18
//and u get null because your value is between 15-18
so try to add other case in that range.
second question because they are strings , not numbers.
try order them by age