union of two queries in one - sql

I have two queries with different result sets but only one of the conditions is additional in one of the queries. Both queries are fetching from the same table.
first query:
SELECT cm.ctm, count_big(*) AS TOTAL
FROM dbo_cm.cm
WHERE
cm.a= 'abc' AND
cm.b= 1 AND
cm.ps IS NOT NULL AND
datepart(MONTH, cm.ps) = 7 AND
datepart(YEAR, cm.ps) = 2015
GROUP BY cm.ctm
second query:
SELECT cm.ctm, count_big(*) AS TOTAL
FROM dbo_cm.cm
WHERE
cm.a= 'abc' AND
cm.b= 1 AND
cm.ps IS NOT NULL AND
datepart(MONTH, cm.ps) = 7 AND
datepart(YEAR, cm.ps) = 2015 and
cm.as>cm.ps
GROUP BY cm.ctm
How do I make this query simpler by merging it into one? We use decode in Oracle for this purpose.

You can merge these two queries into one by moving the additional condition in the second query to a case expression and returning null when the condition is not met. count_big, like any aggregate function, will just ignore the nulls:
SELECT cm.ctm,
COUNT_BIG(*) AS total1,
COUNT_BIG(CASE WHEN cm.as > cm.ps THEN 1 ELSE NULL END) AS total2
FROM dbo_cm.cm
WHERE cm.a= 'abc' AND
cm.b= 1 AND
cm.ps IS NOT NULL AND
DATEPART(MONTH, cm.ps) = 7 AND
DATEPART(YEAR, cm.ps) = 2015 AND
GROUP BY cm.ctm

You can use SUM(CASE...) like:
SELECT
cm.ctm,
count_big(*) AS TOTAL1,
SUM(CASE WHEN cm.[as]>cm.[ps] THEN 1 ELSE 0 END) AS TOTAL2
FROM dbo_cm.cm
WHERE cm.a= 'abc'
AND cm.b= 1
AND cm.ps IS NOT NULL
AND datepart(MONTH, cm.ps) = 7
AND datepart(YEAR, cm.ps) = 2015
GROUP BY cm.ctm

Related

Query to show all months and show values where there are data for the corresponding months

I have a query and it shows the months where there is corresponding data. However, I would like to show all of the months in the year and have the months where there are no data shown as zero.
There is my SQL Statement:
SELECT DATENAME(MONTH, hb_Disputes.OPENED) AS MonthValue,
COUNT(CASE WHEN REV_CLS = 2 THEN 1 END) AS SmallCommercialIndust,
COUNT(CASE WHEN REV_CLS <> 2 THEN 1 END) AS Residential
FROM hb_Disputes
WHERE (hb_Disputes.ASSGNTO = 'E099255') AND (YEAR(hb_Disputes.OPENED) = YEAR(GETDATE()))
GROUP BY hb_Disputes.OPENED
And this is my output:
I also have a table name MonthName that shows all of the months in a year and I know I may need to use this to accomplish what I'm trying to achieve but I'm not sure how to get there:
If you have data in the table for all months, but the where clause is filtering it out, then the simplest method is to extend the conditional aggregation:
SELECT DATENAME(MONTH, d.OPENED) AS MonthValue,
SUM(CASE WHEN d.ASSGNTO = 'E099255' AND d.REV_CLS = 2 THEN 1 ELSE 0 END) AS SmallCommercialIndust,
SUM(CASE WHEN d.ASSGNTO = 'E099255' AND d.REV_CLS <> 2 THEN 1 ELSE 0 END) AS Residential
FROM hb_Disputes d
WHERE YEAR(d.OPENED) = YEAR(GETDATE())
GROUP BY DATENAME(MONTH, d.OPENED)
ORDER BY MIN(d.OPENED);
Note: This does not fix the issue in all cases. It should just be a simple way to modify your query -- and will often work.

SELECT 2 VALUES with different requirement

I'm wondering if it is possible to select 2 values in a single select statement that have different criteria. I know I can achieve above with subquery, just wondering if there is a more efficient way to do it.
Consider the following table:
UserId | CreatedDate
1 | 2018-01-21
2 | 2018-02-21
3 | 2018-03-21
4 | 2018-11-21
5 | 2018-11-21
I wish to select total number of users and also total number of users that joined this month. I can do it with two queries like this:
SELECT COUNT(*)
FROM [Users]
SELECT COUNT(*)
FROM [Users]
WHERE MONTH(CreatedDate) = MONTH(GETDATE()) AND YEAR(CreatedDate) = YEAR(GETDATE())
However, can this be a single select as oppose to two queries?
EDIT: To clear confusion, I'm looking for 2 columns, not two rows.
I beleive this will do what you are looking for:
SELECT COUNT(*),
SUM(CASE WHEN MONTH[CreatedDate] = MONTH(GETDATE()) AND YEAR(CreatedDate) = YEAR(GETDATE()) THEN 1 ELSE 0 END) as SubCountWithCriteria
FROM [Users]
Use conditional aggregation:
SELECT COUNT(*),
SUM(CASE WHEN MONTH(CreatedDate) = MONTH(GETDATE()) AND YEAR(CreatedDate) = YEAR(GETDATE()) THEN 1 ELSE 0 END)
FROM [Users];
Note: MONTH[CreatedDate] makes no sense, so I replaced the square braces with parentheses.
Here is one way
(This gives you two rows, if you want two columns others have shown that solution using CASE)
SELECT 'Total Users', COUNT(*)
FROM [Users]
UNION ALL
SELECT 'Total this month', COUNT(*)
FROM [Users]
WHERE MONTH(CreatedDate) = MONTH(GETDATE()) AND YEAR(CreatedDate) = YEAR(GETDATE())

How to I create a new column in sql using conditional clause?

This code worked until I introduced case clause. All I want to do it to make a new column whose value is 1 is prediciton >0 else O.
SELECT p.cohort_name, DATEPART(Month, date)as mm, AVG(prediction)
CASE WHEN ((p.prediction) < 0 THEN 1 else 0 END) as Z
FROM
rates.rates_cohort_predictions p
Group by 1,2
order by p.cohort_name, DATEPART(Month, date)
As mvp stated, you are missing a select statement delimiter
This is the correct SQL statement
SELECT p.cohort_name,
DATEPART(Month, date) AS mm,
AVG(prediction),
CASE WHEN (
(p.prediction) < 0
THEN 1
ELSE 0
END) AS Z
FROM rates.rates_cohort_predictions AS p
GROUP BY 1,2
ORDER BY p.cohort_name, DATEPART(Month, date)

How to return count in 2 columns?

I have this query. It should return Count for both AWARDED (1) and NOT AWARDED(0) works from works table.
Select Count(w.WorkID)as Total, w.IsAwarded, org.OrganizationName
From Works w
Inner Join MC_MemberShip.Membership.Organization org
ON org.OrganizationID= w.Organization_ID
where Convert(varchar(11), w.OpeningDate) >= Convert(varchar(11), #FromDate)
and Convert(varchar(11), w.OpeningDate) < DATEADD(day, 1, Convert(varchar(11), #ToDate))
and w.IsActive=1 and
ISNULL(w.IsAwarded,0)= 0 and w.Organization_ID= case when #OrgID= -1 then w.Organization_ID else #OrgID end
group by org.OrganizationName, w.IsAwarded
Now this query returns Total count for NOT AWARDED i.e. 0 only but i want to return count for AWARDED too in same query.
Organization TotalAwardedWorks TotalNotAwardedWorks
Town 1 1 2
Town 2 44 33
Your query should look something like this:
select org.OrganizationName,
Count(*) as Total,
sum(case when w.IsAwarded = 0 or w.IsAwarded is null then 1 else 0 end) as TotalNotAward,
sum(case when w.IsAwarded = 1 then 0 else 1 end) as TotalAward
from Works w Inner Join
MC_MemberShip.Membership.Organization org
on org.OrganizationID = w.Organization_ID
where w.OpeningDate >= #FromDate and
w.OpeningDate < dateadd(day, 1, #ToDate) and
w.IsActive = 1 and
(w.Organization_ID = #OrgId or #OrgID= -1)
group by org.OrganizationName;
Notes:
Do not convert dates to strings to perform comparisons. That is just perverse.
Generally, the use of case in the where clause is discouraged. The logic is more clearly represented using or.
You can get what you want by using case to put conditions in the aggregation functions.

SQL Efficiency on Date Range or Separate Tables

I'm calculating historical amount from a table in years(ex. 2015-2016, 2014-2015, etc.) I would like to seek expertise if its more efficient to do it in one batch or repeat the query multiple times filtered by the date required.
Thanks in advance!
OPTION 1:
select
id,
sum(case when year(getdate()) - year(txndate) between 5 and 6 then amt else 0 end) as amt_6_5,
...
sum(case when year(getdate()) - year(txndate) between 0 and 1 then amt else 0 end) as amt_1_0,
from
mytable
group by
id
OPTION 2:
select
id, sum(amt) as amt_6_5
from
mytable
group by
id
where
year(getdate()) - year(txndate) between 5 and 6
...
select
id, sum(amt) as amt_1_0
from
mytable
group by
id
where
year(getdate()) - year(txndate) between 0 and 1
1.
Unless you have resources issues I would go with the CASE version.
Although it has no impact on the results, filtering on the requested period in the WHERE clause might have a significant performance advantage.
2. Your period definition creates overlapping.
select id
,sum(case when year(getdate()) - year(txndate) = 6 then amt else 0 end) as amt_6
-- ...
,sum(case when year(getdate()) - year(txndate) = 0 then amt else 0 end) as amt_0
where txndate >= dateadd(year, datediff(year,0, getDate())-6, 0)
from mytable
group by id
This may be help you,
WITH CTE
AS
(
SELECT id,
(CASE WHEN year(getdate()) - year(txndate) BETWEEN 5 AND 6 THEN 'year_5-6'
WHEN year(getdate()) - year(txndate) BETWEEN 4 AND 5 THEN 'year_4-5'
...
END) AS my_year,
amt
FROM mytable
)
SELECT id,my_year,sum(amt)
FROM CTE
GROUP BY id,my_year
Here, inside the CTE, just assigned a proper year_tag for each records (based on your conditions), after that select a summary for the CTE grouped by that year_tag.