SQL Server -- Join Issue - sql

I have a table with following rows :
SectionId
SectionStatus
1
Assigned
1
Approved
2
Assigned
2
Assigned
3
Assigned
Now I want to fetch the SectionId where al SectionStatus belong to that SectionId are not Approved.
Result expected for above table : 1,2,3
Another Example :
SectionId
SectionStatus
1
Approved
1
Approved
2
Assigned
2
Assigned
3
Assigned
Result expected for above table : 2,3

This looks like aggregation with a conditional count in the HAVING clause.
SELECT t.SectionId
FROM yourtable t
GROUP BY t.SectionId
HAVING COUNT(CASE WHEN t.SectionStatus = 'Approved' THEN 1 END) = 0;
db<>fiddle

One way to get that is by cross-applying the record and check whether that is 'Approved' or not.
Try the following:
select distinct SectionId from yourtable tab
cross apply (select 'Approved' Stat)t
where t.Stat <> tab.SectionStatus
Please see the db<>fiddle here.

Related

How to write a query to find a record which is not processed

I am trying to write a query from a table A which has 2 columns :
ID , STATUS
The Status can be PROCESSING, NOTPROCESSED, FAILED, SUCCESS
When a record is successfully processed, a new record is created in the DB with STATUS as PROCESSED and the ID is the same as the previous NOTPROCESSED record.
The Sample Records in DB would like :
1 NOTPROCESSED
2 PROCESSED
1 PROCESSED
3 NOTPROCESSED
4 NOTPROCESSED
2 PROCESSED
3 NOTPROCESSED
4 NOTPROCESSED
The records can appear as duplicate for NOTPROCESSED.
I have to query the records which are NOTPROCESSED i.e
3 NOTPROCESSED
4 NOTPROCESSED
Its getting quite confusing to write the query.
Can anyone help with the logic.
you may use not exists to get this output.
select distinct a.id,a.status
from table a
where a.status='NOTPROCESSED'
and not exists (select null
from table b
where b.id=a.id
and b.status='PROCESSED')
Group by the ids and take only those groups having no record of status PROCESSED
select id
from your_table
group by id
having sum(case when status = 'PROCESSED' then 1 else 0 end) = 0
or get only the ones with only one kind of status
having count(distinct status) = 1
or use alphabetically the highest status
having max(status) = 'NOTPROCESSED'
Here are a couple of options:
select distinct id from A where id not in (
select id from A where status = 'PROCESSED'
);
select distinct id from A natural left join (
select id from A where status = 'PROCESSED'
) as B where B.id is null;
You can use analytical function as follows:
select * from
(select t.*, count(case when status = 'PROCESSED' then 1 end)
over (partition by ID) as cnt
from your_table t) t
where status = 'NOTPROCESSED' and cnt = 0

SQL aggregate rows with same id , specific value in secondary column

I'm looking to filter out rows in the database (PostgreSQL) if one of the values in the status column occurs. The idea is to sum the amount column if the unique reference only has a status equals to 1. The query should not SELECT the reference at all if it has also a status of 2 or any other status for that matter. status refers to the state of the transaction.
Current data table:
reference | amount | status
1 100 1
2 120 1
2 -120 2
3 200 1
3 -200 2
4 450 1
Result:
amount | status
550 1
I've simplified the data example but I think it gives a good idea of what I'm looking for.
I'm unsuccessful in selecting only references that only have status 1.
I've tried sub-queries, using the HAVING clause and other methods without success.
Thanks
Here's a way using not exists to sum all rows where the status is 1 and other rows with the same reference and a non 1 status do not exist.
select sum(amount) from mytable t1
where status = 1
and not exists (
select 1 from mytable t2
where t2.reference = t1.reference
and t2.status <> 1
)
SELECT SUM(amount)
FROM table
WHERE reference NOT IN (
SELECT reference
FROM table
WHERE status<>1
)
The subquery SELECTs all references that must be excluded, then the main query sums everything except them
select sum (amount) as amount
from (
select sum(amount) as amount
from t
group by reference
having not bool_or(status <> 1)
) s;
amount
--------
550
You could use windowed functions to count occurences of status different than 1 per each group:
SELECT SUM(amount) AS amount
FROM (SELECT *,COUNT(*) FILTER(WHERE status<>1) OVER(PARTITION BY reference) cnt
FROM tc) AS sub
WHERE cnt = 0;
Rextester Demo

Select where count of other query of same table

I have got table "Members" with fields ID,UserID,GroupID
And I would like to select only GroupIDs where count of Members is more than 1 for each members, like this:
ID UserID GroupID
1 1 1 /* we are selecting groups for guy with ID 1, here are 3 people */
2 2 1
3 3 1
4 1 2 /* here the guy is alone in group, ignore him! */
5 1 3 /* select this one too for guy 1, because #members>1 */
6 2 3
Performing group select for guy with ID 1 including that there must be atleast 2 people in same group, so this would return: 1, 3
But I have no idea how to do this in SQL, I would like to do something like this, but, it obviously doesn't work:
SELECT GroupID
FROM Members
WHERE UserID=1
AND COUNT(
SELECT UserID FROM Members WHERE GroupID=**currently iterated group**
)>1;
Is it somehow possible?
If I understand correctly, you want groups with at least two members, one of which has userid = 1. The following query finds these groups using group by and having:
select m.groupId
from Members m
group by m.groupId
having count(*) > 1 and
sum(case when m.userid = 1 then 1 else 0 end) > 0;
This will return the groups with more than one member that user 1 is a member of:
select groupid
from members
where groupid in (select groupid from members where userid = 1)
group by groupid having count(*) > 1;
The solution offered by #GordonLinoff is probably better (more efficient) though.

SQL Query where a specific column should have two specific values but have just one

Sorry for the cryptic title, but i didn't find a better question
I have a Table with lets say these Data:
Table Article
ID ArticleNumber Type
1 10 1
2 10 3
3 20 1
4 30 1
5 30 3
I'm looking for the 3. Row where no type 3 article exists but a type 1 article exists.
I think it have to be a very easy SQL query but i can't find a solution...
To get all ArticleNumbers for which exists a row with type = 1 but there is no row with type = 3, use this:
SELECT
*
FROM
Article a
WHERE
a.`Type` = 1
AND NOT EXISTS (
SELECT * FROM
Article a2
WHERE
a2.`Type` = 3
AND a2.ArticleNumber = a.ArticleNumber
)
You can select the first ID by aggregating the original data (see subquery), then you can filter those records where could be any anomalies.
If you want, you can change the aggregation to COUNT, then you can compare the count for each types.
SELECT
ArticleNumber
FROM (
-- Conditional aggregation to find the first ID for each type per ArticleNumber
SELECT
ArticleNumber
, MIN(CASE WHEN Type = 1 THEN ID ELSE NULL END) AS Type_1
, MIN(CASE WHEN Type = 3 THEN ID ELSE NULL END) AS Type_3
GROUP BY
ArticleNumber
) AS X
WHERE
Type_1 IS NULL
OR Type_2 IS NULL
Note You can change the above query to use the HAVING keyword instead of subquery if you want.
Another variant, using MINUS to remove the articles with Type 3:
select ID, ArticleNumber from Article where type = 1
MINUS
select ID, ArticleNumber from Article where type = 3
UPDATE
After re-reading your question, I guess you want to also have those with Type = 3, but where no row with Type = 1 exists. For this, you can use COUNT DISTINCT:
select * from (
select ID, ArticleNumber, count(distinct type) as type_cnt
from Article
group by ID, ArticleNumber
)
where type_cnt < 2
You mean you want all rows where type is not 3?
That would be this statement:
SELECT
*
FROM
`Article`
WHERE
`type` != 3;
After re-reading your question I understand your problem. I would go with Eriks solution.

Combine Multiple Sql Queries into one

I have a column called "status" in a sql table called "latest" which contains five different values new,deployed,resolved,assigned and closed as shown below
Status
--------------
NEW
NEW
DEPLOYED
NEW
RESOLVED
ASSIGNED
ASSIGNED
RESOLVED
ASSIGNED
NEW
NEW
RESOLVED
CLOSED
ASSIGNED
I want to write a query in which i can count the number of times each of these words occur in the column "status". Currently I'm using count function in 5 different queries like this.
1)select count(status) from latest where status="NEW";
2)select count(status) from latest where status="DEPLOYED";
3)select count(status) from latest where status="RESOLVED";
4)select count(status) from latest where status="ASSIGNED";
5)select count(status) from latest where status="CLOSED";
Is there a way i could combine all these queries into single query without using joins or union to get 5 different count values??
QUERY 1:
SELECT STATUS, COUNT(1) FROM LATEST
GROUP BY STATUS
ORDER BY STATUS;
Your Output would be:
STATUS COUNT
ASSIGNED 4
CLOSED 1
DEPLOYED 1
NEW 5
RESOLVED 3
To get the output in single row with 5 columns you can use:
QUERY 2:
SELECT COUNT(CASE WHEN STATUS='ASSIGNED' THEN 1 END) ASSIGNED_COUNT,
COUNT(CASE WHEN STATUS='CLOSED' THEN 1 END) CLOSED_COUNT,
COUNT(CASE WHEN STATUS='DEPLOYED' THEN 1 END) DEPLOYED_COUNT,
COUNT(CASE WHEN STATUS='NEW' THEN 1 END) NEW_COUNT,
COUNT(CASE WHEN STATUS='RESOLVED' THEN 1 END) RESOLVED_COUNT
FROM LATEST
Your Output would be:
ASSIGNED_COUNT | CLOSED_COUNT | DEPLOYED_COUNT | NEW_COUNT | RESOLVED_COUNT
4 | 1 | 1 | 5 | 3
EXPLANATION:
Query 1 can be used where there can be any number of dynamic status. For example, even if there is a status named DEFERRED, it would automatically be included without query change. But, if there is say, no record with status as "NEW", then no data would be returned.
Query 2 can be used to return all the data in a single row. If a new status is to be included, then the query must be modified. If there are no records for a status, then 0 would be returned. IDEAL FOR DASHBOARD kind of usage.
Try this cool one
Select *
from
(
Select Status,COUNT(*) 'Count'
from LATEST
group by Status with rollup
) t
where t.Count is not null
Try this:
SELECT l.status, COUNT(1)
FROM latest l
GROUP BY l.status;
OR
SELECT SUM(l.status = 'NEW') AS NEW_STATUS,
SUM(l.status = 'DEPLOYED') AS DEPLOYED_STATUS,
SUM(l.status = 'RESOLVED') AS RESOLVED_STATUS,
SUM(l.status = 'ASSIGNED') AS ASSIGNED_STATUS,
SUM(l.status = 'CLOSED') AS CLOSED_STATUS
FROM latest l;
UPDATE
Use SELECT...INTO statement to achieve this, check below query
SELECT SUM(l.status = 'NEW') AS NEW_STATUS,
SUM(l.status = 'DEPLOYED') AS DEPLOYED_STATUS,
SUM(l.status = 'RESOLVED') AS RESOLVED_STATUS,
SUM(l.status = 'ASSIGNED') AS ASSIGNED_STATUS,
SUM(l.status = 'CLOSED') AS CLOSED_STATUS
INTO NEW_STATUS, DEPLOYED_STATUS, RESOLVED_STATUS,
ASSIGNED_STATUS, CLOSED_STATUS
FROM latest l;
Try This...
1.>
Select Count() as Count,Status from latest where (status='NEW' Or status='DEPLOYED' or status='RESOLVED' or status='ASSIGNED' Or status='CLOSED') group by Status;*
OR
2.>
select count(status) from latest where (status='NEW' Or status='DEPLOYED' or status='RESOLVED' or status='ASSIGNED' Or status='CLOSED');