Select Distinct Attribute and Print out Count of another even when the count is 0 - sql

I don't quite know how I should describe the problem for title, but here's my question.
I have a table named hello with two columns named time and state.
Time | State
Here's an example of the data I have
1 DC
1 VA
1 VA
2 DC
2 MD
3 MD
3 MD
3 VA
3 DC
I would like to get all the possible time and the count of "VA" (0 if "VA" doesn't appear at the time)
The output would look like this
Time Number
1 2
2 0
3 1
I tried to do
SELECT DISTINCT time,
COUNT(state) as Number
FROM hello
WHERE state = 'VA'
GROUP BY time
but it doesn't seem to work.

This is a conditional aggregation:
select time, sum(case when state = 'VA' then 1 else 0 end) as NumVA
from hello
group by time
I want to add that you should never use distinct when you have a group by. The two are redundant. Distinct as a keyword is not even needed in the SQL language; semantically, it is just shorthand for grouping by all the columns.

SELECT TIME,
SUM(CASE WHEN State = 'VA' THEN 1 ELSE 0 END)
FROm tableName
GROUP BY Time
SQLFiddle Demo

One rule of thumb is to get your counts first and put them into a temp for use later.
See below:
Create table temp(Num int, [state] varchar(2))
Insert into temp(Num,[state])
Select 1,'DC'
UNION ALL
Select 1,'VA'
UNION ALL
Select 1,'VA'
UNION ALL
Select 2,'DC'
UNION ALL
Select 2,'MD'
UNION ALL
Select 3,'MD'
UNION All
Select 3,'MD'
UNION ALL
Select 3,'VA'
UNION ALL
Select 3,'DC'
Select t.Num [Time],t.[State]
, CASE WHEN t.[state] = 'VA' THEN Count(t.[State]) ELSE 0 END [Number]
INTO #temp2
From temp t
Group by t.Num, t.[state]
--drop table #temp2
Select
t2.[time]
,SUM(t2.[Number])
From #temp2 t2
group by t2.[time]

Related

Check whether an employee is present on three consecutive days

I have a table called tbl_A with the following schema:
After insert, I have the following data in tbl_A:
Now the question is how to write a query for the following scenario:
Put (1) in front of any employee who was present three days consecutively
Put (0) in front of employee who was not present three days consecutively
The output screen shoot:
I think we should use case statement, but I am not able to check three consecutive days from date. I hope I am helped in this
Thank you
select name, case when max(cons_days) >= 3 then 1 else 0 end as presence
from (
select name, count(*) as cons_days
from tbl_A, (values (0),(1),(2)) as a(dd)
group by name, adate + dd
)x
group by name
With a self-join on name and available = 'Y', we create an inner table with different combinations of dates for a given name and take a count of those entries in which the dates of the two instances of the table are less than 2 units apart i.e. for each value of a date adate, it will check for entries with its own value adate as well as adate + 1 and adate + 2. If all 3 entries are present, the count will be 3 and you will have a flag with value 1 for such names(this is done in the outer query). Try the below query:
SELECT Z.NAME,
CASE WHEN Z.CONSEQ_AVAIL >= 3 THEN 1 ELSE 0 END AS YOUR_FLAG
FROM
(
SELECT A.NAME,
SUM(CASE WHEN B.ADATE >= A.ADATE AND B.ADATE <= A.ADATE + 2 THEN 1 ELSE 0 END) AS CONSEQ_AVAIL
FROM
TABL_A A INNER JOIN TABL_A B
ON A.NAME = B.NAME AND A.AVAILABLE = 'Y' AND B.AVAILABLE = 'Y'
GROUP BY A.NAME
) Z;
Due to the complexity of the problem, I have not been able to test it out. If something is really wrong, please let me know and I will be happy to take down my answer.
--Below is My Approch
select Name,
Case WHen Max_Count>=3 Then 1 else 0 end as Presence
from
(
Select Name,MAx(Coun) as Max_Count
from
(
select Name, (count(*) over (partition by Name,Ref_Date)) as Coun from
(
select Name,adate + row_number() over (partition by Name order by Adate desc) as Ref_Date
from temp
where available='Y'
)
) group by Name
);
select name as employee , case when sum(diff) > =3 then 1 else 0 end as presence
from
(select id, name, Available,Adate, lead(Adate,1) over(order by name) as lead,
case when datediff(day, Adate,lead(Adate,1) over(order by name)) = 1 then 1 else 0 end as diff
from table_A
where Available = 'Y') A
group by name;

Select distinct count after count?

I'll cut right to the chase: I have a select I'm currently writing with a rather lengthy where clause, what I want to do is calculate percentages.
So what I need is the count of all results and then my each distinct counts.
SELECT distinct count(*)
FROM mytable
WHERE mywhereclause
ORDER BY columnIuseInWhereClause
works fine for getting each individual values, but I want to avoid doing something like
Select (Select count(*) from mytable WHERE mywhereclause),
distinct count(*)
FROM mytable
WHERE mywhereclause
because I'd be using the same where-clause twice which just seems unnecessary.
This is for OracleDB but I'm only using standard SQL syntax, nothing database specific if I can help it.
Thanks for any ideas.
Edit:
Sample Data
__ID__,__someValue__
1 | A
2 | A
3 | B
4 | C
I want the occurances of A, B, C as numbers as well as the overall count.
__CountAll__,__ACounts__,__BCounts__,__CCounts__
4 | 2 | 1 | 1
So I can get to
100% | 50% | 25% | 25%
That last part I can probably figure out on my own. Excuse my lack of experience or even logic thinking, it's early in the morning. ;)
Edit2:
I do have written a query that works but is clumsy and long as all holy heck, this one is for trying with group by.
Try:
select count(*) as CountAll,
count(distinct SomeColumn) as CoundDistinct -- The DISTINCT goes inside the brackets
from myTable
where SomeOtherColumn = 'Something'
Use case expressions to do conditional counting:
select count(*) as CountAll,
count(case when someValue = 'A' then 1 end) as ACounts,
count(case when someValue = 'B' then 1 end) as BCounts,
count(case when someValue = 'C' then 1 end) as CCounts
FROM mytable
WHERE mywhereclause
Wrap it up in a derived table to do the % part easy:
select 100,
ACounts * 100 / CountAll,
BCounts * 100 / CountAll,
CCounts * 100 / CountAll
from
(
select count(*) as CountAll,
count(case when someValue = 'A' then 1 end) as ACounts,
count(case when someValue = 'B' then 1 end) as BCounts,
count(case when someValue = 'C' then 1 end) as CCounts
FROM mytable
WHERE mywhereclause
) dt
Here's an alternative using window function:
with data_table(ID, some_value)
AS
(SELECT 1,'A' UNION ALL
SELECT 2,'A' UNION ALL
SELECT 3,'B' UNION ALL
SELECT 4,'C'
)
SELECT DISTINCT [some_value],
COUNT([some_value]) OVER () AS Count_All,
COUNT([some_value]) OVER (PARTITION BY [some_value]) AS 'Counts' FROM [data_table]
ORDER BY [some_value]
The advantage is that you don't have to hard-code your [some_value]

SQL, return select results with different where clauses

I have table whose column is just the length of a session and I would like to return the number of session that have zero length and the number of sessions that have length greater than zero.
I can do that with two separate commands
select count(session_length) from my_table where session_length=0
select count(session_length) from my_table where session_length>0
But I would like to see the results combined in one table
You can do it with one query using conditional aggregation.
select
count(case when session_length = 0 then 1 end),
count(case when session_length > 0 then 1 end)
from my_table
select 1 as QryNo, count(session_length) as SessLen
from my_table
where session_length=0
union
select 2 as QryNo, count(session_length) as SessLen
from my_table
where session_length>0
or
select
case
when session_length = 0 then 1
else 2
end as QryNo,
count(session_length) as SessLen
from my_table
This may be too simple so apologies if I have misread your query but Can you use
select count(session_length) from my_table where session_length >= 0
Again, Apologies if this is not what you're looking for.

SQL getting values that apear once, not distinct

Having touble getting only values that appear once. I currently have some sql code that gets out the all the entries that have 0 percent. The problem is that two rows can contain the same person With different percentages. If one of these is above 0 then i dont want it to come out in the Query
abridged table:
Name - Percent
steve 0
dan 0
mike 100
harold 50
steve 80
carl 0
carl 0
Result:
dan - 0
Carl - 0
Here is how far ive gotten, but not managed to make any variation of Count() or having or Group by working.
select person, Value2, Value3, Value4, percent
from
Table1
INNER JOIN Table1 ON Table2.valueNum = Table1.valueNum
INNER JOINTable1 ON Table3.valueNum = Table1.valueNum
INNER JOIN Table1 ON Table4.valueNum = Table1.valueNum
WHERE
(#date BETWEEN table1.FROMDATE AND table1.todate)
AND table1.percent = 0
AND table1.varchar IN ('T', 'X')
This is one method
select name,0 as percent from abridged
group by name
having min(percent)=0 and max(percent)=0
Your example SQL and abridged table don't match. However, this looks like the basic idea you are after:
select
*
from
dbo.table a
where
a.percent = 0 and
not exists (
select
'x'
from
dbo.table b
where
a.Name = b.Name and
b.percent > 0
);
I would just use window functions:
with t as (
<your query here>
)
select t.*
from (select t.*, count(*) over (partition by name) as cnt
from t
) t
where cnt = 1;
To resolve your problem you can use this query:
select [name], 0 as [percent] from [abridged]
group by [name]
having sum([percent])=0
This should solve your problem right?
select name,sum([percent]) from abridged
group by name
having SUM([percent]) = 0
Query
SELECT distinct name, min(percentage) from a
group by name
having min(percentage) = 0
and count(*) > 1;

Get the distinct count of values from a table with multiple where clauses

My table structure is this
id last_mod_dt nr is_u is_rog is_ror is_unv
1 x uuid1 1 1 1 0
2 y uuid1 1 0 1 1
3 z uuid2 1 1 1 1
I want the count of rows with:
is_ror=1 or is_rog =1
is_u=1
is_unv=1
All in a single query. Is it possible?
The problem I am facing is that there can be same values for nr as is the case in the table above.
Case statments provide mondo flexibility...
SELECT
sum(case
when is_ror = 1 or is_rog = 1 then 1
else 0
end) FirstCount
,sum(case
when is_u = 1 then 1
else 0
end) SecondCount
,sum(case
when is_unv = 1 then 1
else 0
end) ThirdCount
from MyTable
you can use union to get multiple results e.g.
select count(*) from table with is_ror=1 or is_rog =1
union
select count(*) from table with is_u=1
union
select count(*) from table with is_unv=1
Then the result set will contain three rows each with one of the counts.
Sounds pretty simple if "all in a single query" does not disqualify subselects;
SELECT
(SELECT COUNT(DISTINCT nr) FROM table1 WHERE is_ror=1 OR is_rog=1) cnt_ror_reg,
(SELECT COUNT(DISTINCT nr) FROM table1 WHERE is_u=1) cnt_u,
(SELECT COUNT(DISTINCT nr) FROM table1 WHERE is_unv=1) cnt_unv;
how about something like
SELECT
SUM(IF(is_u > 0 AND is_rog > 0, 1, 0)) AS count_something,
...
from table
group by nr
I think it will do the trick
I am of course not sure what you want exactly, but I believe you can use the logic to produce your desired result.