Combining separate queries from the same table as separate columns - sql

I have a query that I am trying to combine but with different columns. The specifics of this are:
Same table
Different Where clause
Oracle DB
Ran in DBVisualizer
This is what I was trying to do: it runs but it does not join the two columns. they are being outputted into separate Result tabs in DBVisualizer
Select count (distinct CODE) AS Comp_PCT
from cons.GM
Where POLICY='NR'
And PCT is null
UNION
Select count (distinct CODE) AS Comp_DTY
from cons.GM
Where POLICY='NR'
And DTY is null

I don't know that this answer is a correct form:
SELECT
(Select count (distinct CODE)
from cons.GM
Where POLICY='NR'
And PCT is null) AS Comp_PCT,
(Select count (distinct CODE)
from cons.GM
Where POLICY='NR'
And DTY is null) AS Comp_DTY

Related

Aggregating based on GROUPING of multiple columns

I am trying to subquery and aggregate in SQL after doing an initial query with multiple joins. My ultimate goal is to get a count (or a sum) of specimens tested based on a grouping of multiple columns. This is slightly different from SQL Server query - Selecting COUNT(*) with DISTINCT and SQL Server: aggregate error on grouping.
The three tables that I use (PERSON, SPECIMEN, TEST), have 1-many relationships. So PERSON has many SPECIMENS and those SPECIMENS have many TESTS. I did three inner joins to combine these tables plus an additional table (ANALYSIS).
WITH TALLY as (
SELECT PERSON.NAME, PERSON.PHASE, TEST.DATE_STARTED, TEST.ANALYSIS, SPECIMEN.GROUP, TEST.STATUS,
ANALYSIS.ANALYSIS_TYPE, SPECIMEN.SPECIMEN_NUMBER
FROM DB.TEST
INNER JOIN
DB.SAMPLE ON
TEST.SPECIMEN_NUMBER = SPECIMEN.SPECIMEN_NUMBER
INNER JOIN
DB.PRODUCT ON
SPECIMEN.PERSON = PERSON.NAME
INNER JOIN
DB.ANALYSIS ON
TEST.ANALYSIS = ANALYSIS.NAME
WHERE PERSON.NAME = 'Joe'
AND TEST.DATE_STARTED >= '20-DEC-16' AND TEST.DATE_STARTED <='01-APR-18'
AND PERSON.PHASE = 'PHASE1'
ORDER BY TEST.DATE_STARTED)
SELECT COUNT(DISTINCT ANALYSIS) as SPECIMEN_COUNT, DATE_STARTED, ANALYSIS, STATUS, GROUP, ANALYSIS_TYPE
FROM TALLY
GROUP BY DATE_STARTED, ANALYSIS, STATUS, GROUP, ANALYSIS_TYPE
ORDER BY DATE_STARTED;
This gives me the repeated columns: first grouping repeated 4 times
What I am trying to see is: aggregated first grouping with total count
Any thoughts as to what is missing? SUM instead of COUNT or in addition to COUNT creates an error. Thanks in advance!
9/17/2020 Update: I have tried adding a subquery because I also need to use a new column of metadata (ANALYSIS_TYPE_ALIAS) which is created in the first query through a CASE STATEMENT(...). I have also tried using another subquery with inner join to count based on those conditions to a temp table, but still cannot seem to aggregate to flatten the table. Here is my current attempt:
WITH TALLY as (
SELECT PERSON.NAME, PERSON.PHASE, TEST.DATE_STARTED, TEST.ANALYSIS, SPECIMEN.GROUP, TEST.STATUS,
ANALYSIS.ANALYSIS_TYPE...
FROM DB.TEST
INNER JOIN
DB.SAMPLE ON
TEST.SPECIMEN_NUMBER = SPECIMEN.SPECIMEN_NUMBER
INNER JOIN
DB.PRODUCT ON
SPECIMEN.PERSON = PERSON.NAME
INNER JOIN
DB.ANALYSIS ON
TEST.ANALYSIS = ANALYSIS.NAME
WHERE PERSON.NAME = 'Joe'
AND TEST.DATE_STARTED >= '20-DEC-16' AND TEST.DATE_STARTED <='01-APR-18'
AND PERSON.PHASE = 'PHASE1'
ORDER BY TEST.DATE_STARTED),
SUMMARY_COMBO AS (SELECT DISTINCT(CONCAT(CONCAT(CONCAT(CONCAT(ANALYSIS, DATE_STARTED),STATUS), GROUP), ANALYSIS_TYPE_ALIAS))AS UUID,
TALLY.NAME, TALLY.PHASE, TALLY.DATE_STARTED, TALLY.ANALYSIS, TALLY.GROUP, TALLY.STATUS, TALLY.ANALYSIS_TYPE_ALIAS
FROM TALLY)
SELECT SUMMARY_COMBO.NAME, SUMMARY_COMBO.PHASE, SUMMARY_COMBO.DATE_STARTED, SUMMARY_COMBO.ANALYSIS,SUMMARY_COMBO.GROUP, SUMMARY_COMBO.STATUS, SUMMARY_COMBO.ANALYSIS_TYPE_ALIAS,
COUNT(SUMMARY_COMBO.ANALYSIS) OVER (PARTITION BY SUMMARY_COMBO.UUID) AS SPECIMEN_COUNT
FROM SUMMARY_COMBO
ORDER BY SUMMARY_COMBO.DATE_STARTED;
This gave me the following table Shows aggregated counts, but doesn't aggregate based on unique UUID. Is there a way to take the sum of the count? I've tried to do this by storing count to a subquery and then referencing that count variable, but I am missing something in how to group the 8 columns of data that I want to show + the count of that combination of columns.
Thanks!
Just remove analysis from the group by clause, since that's the column whose distinct values you want to count. Otherwise, the query generates more groups than what you need (and the count of distinct analysis values in each group is always 1).
WITH TALLY as ( ...)
SELECT COUNT(DISTINCT ANALYSIS) as SPECIMEN_COUNT, DATE_STARTED, ANALYSIS, STATUS, GROUP, ANALYSIS_TYPE
FROM TALLY
GROUP BY DATE_STARTED, STATUS, GROUP, ANALYSIS_TYPE
ORDER BY DATE_STARTED;

How do I count the rows with a where clause in SQL Server?

I am pretty much stuck with a problem I am facing with SQL Server. I want to show in a query the amount of times that specific value occurs. This is pretty easy to do, but I want to take it a step further and I think the best way to explain on what I am trying to achieve is to explain it using images.
I have two tables:
Plant and
Chest
As you can see with the chest the column 'hoeveelheid' tells how full the chest is, 'vol' == 1 and 3/4 is == 0,75. In the plant table there is a column 'Hoeveelheidperkist' which tells how much plants there can be in 1 chest.
select DISTINCT kist.Plantnaam, kist.Plantmaat, count(*) AS 'Amount'
from kist
group by kist.plantnaam, kist.Plantmaat
This query counts all the chests, but it does not seperate the count of 'Vol' chests and '3/4' chests. It only does This. What I want to achieve is this. But I have no idea how. Any help would be much appreciated.
If you use group by you don't need distinct
and if you want the seprated count for hoeveelheid you ust add to the group by clause
select DISTINCT kist.Plantnaam, kist.Plantmaat, kist.hoeveelheid, count(*) AS 'Amount'
from kist
group by kist.plantnaam, kist.Plantmaat, hoeveelheid
or if you want all the 3 count ond the samw rowx you could use a condition aggreagtion eg:
select DISTINCT kist.Plantnaam, kist.Plantmaat
, sum(case when kist.hoeveelheid ='Vol' then 1 else 0 end) vol
, sum(case when kist.hoeveelheid ='3/3' then 1 else 0 end) 3_4
, count(*) AS 'Amount'
from kist
group by kist.plantnaam, kist.Plantmaat
When you want to filter the data on the counts you have to use having clause. When ever you are using aggregate functions(sum, count, min, max) and you want to filter them on aggregation basis, use having clause
select DISTINCT kist.Plantnaam, kist.Plantmaat, count(*) AS 'Amount'
from kist
group by kist.plantnaam, kist.Plantmaat having count(*) = 1 -- or provide necessary conditions

How to pull distinct counts from two different tables at once at align rows

I have two separate tables: emr and treatment. Each table has a userID column and a provider column. Currently, I'm doing a simple pull to count the number of distinct userIDs that appear in the emr table like this:
SELECT distinct vender, count (distinct userID) AS EMR_Patients
from emr
group by 1
This gets me the following output:
vender | EMR_Patients
+++++++++++++++++++++
a 10,000
b 5,000
c 37,500
However, I want to include the number of userIDs that also appear in the treatment table so I can see how many userID's that have an emr record and also have a treatment of interest. The output I'm trying to get is:
vender | EMR_Patients| Treatment_Patients
+++++++++++++++++++++++++++++++++++++++++
a 10,000 4,000
b 5,000 3,000
c 37,500 9,000
I tried using a union:
SELECT distinct vender, count (distinct userID) AS EMR_Patients
FROM emr
GROUP BY 1
UNION ALL
(SELECT distinct vender, count (distinct userID) AS Treatment_Patients
FROM treatment
GROUP BY 1)
But this doesn't work correctly. Is there a way to do this as a union, or should I left join the two tables together beforehand? Or maybe there's a cleaner way than either of these options?
Use JOIN:
SELECT e.vendor, e.EMR_Patients, t.Treatment_Patients
FROM (SELECT vendor, count(distinct userID) AS EMR_Patients
FROM emr
GROUP BY 1
) e
(SELECT vendor, count(distinct userID) AS Treatment_Patients
FROM treatment
GROUP BY 1
) t
ON e.vendor = t.vendor;
(I adjusted the spelling of "vendor".)
This will only include vendors in both tables. If you want vendors that are missing from one of the tables, you need an outer join of some sort. Your question is not clear on that.

Compare sums of two columns in sql

I have two tables with a column named no_id, I want to test that the values in both columns on the tables are the same.
So I´m trying to sum the values of both columns and compare the result.
SELECT
CASE
WHEN SUM (cast(a.no_id as bigint)) = SUM(cast(b.no_id as bigint)) THEN 'YES'
ELSE 'NO'
END as no_id
FROM table_a as a
,table_b as b
The result of the query is NO, but when I select each sum:
SELECT
SUM (cast(a.no_id as bigint)),
SUM(cast(b.no_id as bigint))
FROM table_a as a
,table_b as b
I got two nulls, one in each column. Instead of the sums of the columns.
I have to do this with other twenty columns of both tables.
no_id is a varchar(16) in both tables.
------UPDATE------
no_id only contains numeric strings,
I did the next query to ensure that null would be treated as 0:
SELECT
SUM(cast(ISNULL(a.no_id,0) as bigint)),
SUM(cast(ISNULL(b.no_id,0) as bigint))
FROM table_a as a
,table_b as b
But I keep getting the same result.
If I select the result from just one table, it works, I get the result of the sum:
SELECT
SUM(cast(ISNULL(a.no_id,0) as bigint))
FROM table_a as a
Then, why it doesn't work with both tables?
As I said in the comments:
Don't use the comma(,) operator in the FROM clause, it's been obsolete for over twenty years, use the JOIN keyword syntax instead. Because if you did you would know that ...
You are CROSS JOIN-ing your tables which is very bad and logically wrong 99% of the time. You need to use column subqueries instead.
Like this:
SELECT
CASE
WHEN (SELECT SUM(cast(no_id as bigint)) FROM table_a)
= (SELECT SUM(cast(no_id as bigint)) FROM table_b) THEN 'YES'
ELSE 'NO'
END as no_id
The problem is you don't say how table_a and table_b are related, so every row in table_a is paired with every row in table_b if either table has even one null value, then the total sum will be null.
If you just want the SUMS in both tables to match, then I;m not sure SUM is the best indicator. If table A had the values 1 and 4, and table b had 2 and 3, then the SUM would match but obviously the values are different.

filtering rows by checking a condition for group in one statement only

I have the following statement:
SELECT
(CONVERT(VARCHAR(10), f1, 120)) AS ff1,
CONVERT(VARCHAR(10), f2, 103) AS ff2,
...,
Bonus,
Malus,
ClientID,
FROM
my_table
WHERE
<my_conditions>
ORDER BY
f1 ASC
This select returns several rows for each ClientID. I have to filter out all the rows with the Clients that don't have any row with non-empty Bonus or Malus.
How can I do it by changing this select by one statement only and without duplicating all this select?
I could store the result in a #temp_table, then group the data and use the result of the grouping to filter the temp table. - BUT I should do it by one statement only.
I could perform this select twice - one time grouping it and then I can filter the rows based on grouping result. BUT I don't want to select it twice.
May be CTE (Common Table Expressions) could be useful here to perform the select one time only and to be able to use the result for grouping and then for selecting the desired result based on the grouping result.
Any more elegant solution for this problem?
Thank you in advance!
Just to clarify what the SQL should do I add an example:
ClientID Bonus Malus
1 1
1
1 1
2
2
3 4
3 5
3 1
So in this case I don't want the ClientID=2 rows to appear (they are not interesting). The result should be:
ClientID Bonus Malus
1 1
1
1 1
3 4
3 5
3 1
SELECT Bonus,
Malus,
ClientID
FROM my_table
WHERE ClientID not in
(
select ClientID
from my_table
group by ClientID
having count(Bonus) = 0 and count(Malus) = 0
)
A CTE will work fine, but in effect its contents will be executed twice because they are being cloned into all the places where the CTE is being used. This can be a net performance win or loss compared to using a temp table. If the query is very expensive it might come out as a loss. If it is cheap or if many rows are being returned the temp table will lose the comparison.
Which solution is better? Look at the execution plans and measure the performance.
The CTE is the easier, more maintainable are less redundant alternative.
You haven't specified what are data types of Bonus and Malus columns. So if they're integer (or can be converted to integer), then the query below should be helpful. It calculates sum of both columns for each ClientID. These sums are the same for each detail line of the same client so we can use them in WHERE condition. Statement SUM() OVER() is called "windowed function" and can't be used in WHERE clause so I had to wrap your select-list with a parent one just because of syntax.
SELECT *
FROM (
SELECT
CONVERT(VARCHAR(10), f1, 120) AS ff1,
CONVERT(VARCHAR(10), f2, 103) AS ff2,
...,
Bonus,
Malus,
ClientID,
SUM(Bonus) OVER (PARTITION BY ClientID) AS ClientBonusTotal,
SUM(Malus) OVER (PARTITION BY ClientID) AS ClientMalusTotal
FROM
my_table
WHERE
<my_conditions>
) a
WHERE ISNULL(a.ClientBonusTotal, 0) <> 0 OR ISNULL(a.ClientMalusTotal, 0) <> 0
ORDER BY f1 ASC