How to summarize table based on other column values? - sql

There is a decision table as follows:
Id decision
1 NULL
1 NULL
1 yes
1 NULL
2 no
2 no
2 no
3 yes
3 no
3 yes
The result should return :
Id decision
1 Decision Pending
2 no
3 yes
So for each Id in the decision table:
If any of the decision value is NULL then it is to be set to
"decision pending". eg. id 1
If there is no NULL and any of the decision is yes then final
decision is set to be "yes". eg. id 3
If there is no NULL and all the decisions are no then final decision
is set to be as "no". eg. id 2
What should the azure sql query to get the above mentioned result?
P.S. I am new to SQL, so having trouble figuring this out.

SELECT
id,
CASE
WHEN COUNT(*) > COUNT(decision)
THEN 'pending'
ELSE MAX(decision)
END
AS decision
FROM
decision
GROUP BY
id
GROUP BY id ensures that you get one row per id.
COUNT(*) tells you how many rows there are for that id.
COUNT(decision) tell you how many of those rows have NOT NULL decisions.
COUNT(*) > COUNT(decision) is therfore TRUE if any of the decisions in the group are NULL.
MAX(decision) returns yes if there are any yes values in the group, and no only if there aren't any yes values in the group.

One way is to compare the count(*) and count(decision) which reveals if a row is null and use an inline if to succinctly know to use the aggregate
select id, Iif(Count(*)=Count(decision),Max(decision),'Decision Pending')
from Decision
group by id

Related

Filtering a column based on having some value in one of the rows in SQL or Presto Athena

I am trying in Athena to output only users which have some specific value in them but not in all of the rows
Suppose I have the table below.
I want all users which have value '100' in at least one of their rows but also having in other rows value different than 100.
user | value
A | 1
B | 2
A | 100
D | 3
A | 4
C | 3
C | 5
D | 100
So in this example I would want to get only users A and D because only them having 100 and none 100.
I tried maybe grouping by user and creating an array of values per user and then checking if array contains 100 but I don't manage doing it presto.
Also I thought about converting rows to columns and then checking if one of columns equals 100.
Those solutions are too complex? Anybody knows how to implement them or anyone has a better simpler solution?
The users that have at least one value of 100 can be found with this SQL:
SELECT DISTINCT user
FROM some_table
WHERE value = 100
But I assume you are after all tuples of user and value where the user has at least one value of 100, this can be accomplished by using the query above in a slightly more complex query:
WITH matching_users AS (
SELECT DISTINCT user
FROM some_table
WHERE value = 100
)
SELECT user, value
FROM matching_users
LEFT JOIN some_table USING (user)
You can use sub query as below to achieve your required output=
SELECT * FROM your_table
WHERE User IN(
SELECT DISTINCT User
FROM your_table
WHERE Value = 100
)
If you just want the users, I would go for aggregation:
select user
from t
group by user
having sum(case when value = 100 then 1 else 0 end) > 0;
If 100 is the maximum possible value, this can be simplified to:
having max(value) = 100

Sort by specific order, including NULL, postgresql

best explained with an example:
So I have users table:
id name product
1 second NULL
2 first 27
3 first 27
4 last 6
5 second NULL
And I would like to order them in this product order: [27,NULL, 6]
So I will get:
id name product
2 first 27
3 first 27
1 second NULL
5 second NULL
4 last 6
(notice user id 3 can be before user id 2 since they both have the same product value)
Now without NULL I could do it like that:
SELECT id FROM users ORDER BY users.product=27, users.product=6;
How can I do it with NULL ?
p.s.
I would like to do that for many records so it should be efficient.
You can use case to produce custom sort order:
select id
from users
order by case
when product = 27
then 1
when product is null
then 2
when product = 6
then 3
end
As a note, you can follow your original approach. You just need a NULL-safe comparison:
SELECT id
FROM users
ORDER BY (NOT users.product IS DISTINCT FROM 27)::int DESC,
(user.product IS NULL)::int DESC,
(NOT users.product IS DISTINCT FROM 6)::int DESC;
The reason your version has unexpected results is because the first comparison can return NULL, which is ordered separately from the "true" and "false".

Select query to fetch required data from SQL table

I have some data like this as shown below:
Acc_Id || Row_No
1 1
2 1
2 2
2 3
3 1
3 2
3 3
3 4
and I need a query to get the results as shown below:
Acc_Id || Row_No
1 1
2 3
3 4
Please consider that I'm a beginner in SQL.
I assume you want the Count of the row
SELECT Acc_Id, COUNT(*)
FROM Table
GROUP BY Acc_Id
Try this:
select Acc_Id, MAX(Row_No)
from table
group by Acc_Id
As a beginner then this is your first exposure to aggregation and grouping. You may want to look at the documentation on group by now that this problem has motivated your interest in a solutions. Grouping operates by looking at rows with common column values, that you specify, and collapsing them into a single row which represents the group. In your case values in Acc_Id are the names for your groups.
The other answers are both correct in the the final two columns are going to be equivalent with your data.
select Acc_Id, count(*), max(Row_No)
from T
group by Acc_Id;
If you have gaps in the numbering then they won't be the same. You'll have to decide whether you're actually looking for a count of rows of a maximum of a value within a column. At this point you can also consider a number of other aggregate functions that will be useful to you in the future. (Note that the actual values here are pretty much meaningless in this context.)
select Acc_Id, min(Row_No), sum(Row_No), avg(Row_No)
from T
group by Acc_Id;

SQL : Check if result = number for each id

I have this sort of structure
ID STATUS
1 FIRSTSTAT
2 FIRSTSTAT
3 FIRSTSTAT
1 SECSTAT
3 SECSTAT
3 THIRDSTAT
3 FOURTHSTAT
3 FIFTHSTAT
I want to get the 3 back because he has all following status (FIRSTSTAT, SECSTAT, THIRDSTAT). Do you have an idea how I could make that?
It should be done by explicitely giving the statuses because other statuses exist so SELECT FROM WHERE = 'THIRDSTAT' is not ok since it should have all three statuses, not only one of them.
So I guess it should be done calculating the SUM or something like that.
I tried the following but of course, it does not work :
SELECT
FROM
WHERE
AND
AND
If the number of different status values is known to always be 3:
select id
from tablename
where status in ('FIRSTSTAT', 'SECSTAT', 'THIRDSTAT')
group by id
having count(distinct status) = 3

Eliminate Multiple Records In Query

I have a select I want only one record returned for each case and am having a problem with it.
Example:
Select
CaseId, Party_id, RANKING
from...
The problem is at the charge level the case can have similar multiple charges...
Charges
Case ChargeCount RANKING
1 1 800
2 1 802
2 2 803
3 1 800
I only want 3 cases returned with the first charge meeting the criteria selected.
I tried using a simple partition by over caseId but this messed up the counts elsewhere.
Is there other ways to do this???
Thanks
How about:
SELECT CaseId, ChargeCount, Ranking FROM SomeTable WHERE ChargeCount = 1
Unless I'm missing something, it's that simple. Your example query is not exactly very illuminating to the underlying structures that you have presented.
Assuming you want exactly one row returned per CaseID:
Select
CaseId, Party_id, RANKING
from...
GROUP BY CaseID
Note that where there are multiple possible answers for each row, this will return an arbitrary one unless you define somehow the one to pick.