how to fetch data from table based on column value and group by its name and count column value - sql

This is body of the table:
ID STATUS
1 Pending
2 Received
3 NULL
4 NULL
I have four categories of status- Pending, Received, Resolved & Rejected. At first any data is received from my website then this record shown as pending record. So, I want to count the status by their names, like -
STATUS TOTAL
Pending 1
Received 1
Resolved 0
Rejected 0
The problem is that I face, in that table their is no Resolved and Rejected data. So how could I show the output as 0.

You need a table of statuses from which you can outer join to your aggregated results:
with tot as (
select status, Count(*) tot
from t
where status is not null
group by status
)
select s.status, IsNull(t.tot,0) total
from (values ('Pending'),('Received'),('Resolved'),('Rejected'))s(status)
left join tot t on t.status=s.status

Related

How to write oracle sql query for selecting single record which is having highest status

Assume that have a scenario like in request table with same request Id I may have multiple records with different statuses
status like Draft, InProgress, Approved, Completed . we need to fetch single highest status record. Here preferred order is Completed -> Approved -> InProgress -> Draft.
if have three records like one is with InProgress, one with Approved and another one is with Completed, then among these three in need fetch only one record which have highest status Completed.
if have two records like one is with InProgress and another one is with Draft, then among these two in need fetch only one record which have highest status InProgress.
Could any one please suggest me on this ?
Use the ROW_NUMBER analytic function to order the rows based on a CASE expression that converts your string values to priorities:
SELECT *
FROM (
SELECT t.*,
ROW_NUMBER() OVER (
PARTITION BY request_id
ORDER BY CASE status
WHEN 'Completed' THEN 1
WHEN 'Approved' THEN 2
WHEN 'InProgress' THEN 3
WHEN 'Draft' THEN 4
ELSE 5
END
) as rn
FROM table_name t
)
WHERE rn = 1;
Its a bit of an heinous solution (tested on postgresql) - but you can convert your textual status into a number with a CASE statement and then use that plus a subquery to get the highest status:
SELECT rt.*
FROM
(SELECT
id,
MAX(CASE
WHEN status = 'Draft' THEN 0
WHEN status = 'InProgress' THEN 10
WHEN status = 'Approved' THEN 20
WHEN status = 'Completed' THEN 30
END) AS msid
FROM
request_table
GROUP BY
id) max_per_id
INNER JOIN
request_table rt ON max_per_id.id = rt.id
AND max_per_id.msid = CASE WHEN rt.status='Draft' THEN 0 WHEN rt.status='InProgress' then 10 WHEN rt.status='Approved' THEN 20 WHEN rt.status='Completed' then 30 END
The subquery
SELECT
id,
MAX(CASE
WHEN status = 'Draft' THEN 0
WHEN status = 'InProgress' THEN 10
WHEN status = 'Approved' THEN 20
WHEN status = 'Completed' THEN 30
END) AS msid
FROM
request_table
GROUP BY
id) max_per_id
provides the highest numeric status for each id. That then gets joined on the id and the numeric version of the status with the original table

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: Get count of rows for values in another column even when those values do not exist

I have a table named 'products' with two columns: name and status.
I would like to get the count of rows in the table with statuses as Draft, Published and Rejected.
This is the query I tried,
select count(*), status from products where status in ('Draft', 'Published') group by status;
At the moment the table does not have any row with the status as Published or Rejected.
So the above query just returns one row with status and Draft along with its count
count | status
-------+--------
24 | Draft
However, I would like to the query result with the other statuses as zero.
count | status
-------+--------
24 | Draft
0 | Published
0 | Rejected
How should I write the query so that I get the results as above?
You need a list of the statuses and a left join:
select v.status, count(p.status)
from (values ('Draft'), ('Published'), ('Rejected')
) v(status) left join
products p
on p.status = v.status
group by v.status;

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

SQL view with a column that shows top result of relationship with multiple weightings

I have three tables, an Objects table, a Status table and a StatusTypes Table.
An Object has Multiple Status' which each has a status type. I would like to create a view that gives me the objects ID, and Most Important Status Description which is found in the StatusTypes table, and the most important status Date which is in the Status Table.
The part I am getting hung up on is to find the most Important Status It must first be sorted by the latest date, then by a integer weighting (Priority) in the Status Table then again by another weighting in the StatusTypes Table (Weighting)
What would be the best SQL statement to quickly deliver these results.
Objects
ID Aquisiton Date Serial Number
127237 1997-04-21 2151513515
127239 1997-10-31 2151513523
127242 1998-01-20 2165588481
127272 1998-10-20 2195689842
127286 1999-06-15 2231549489
127291 1999-06-01 2229564978
Status
ID ObjectID Priority StatusMessage Date Status
1 127237 1 Online 22.02.12 07.01.00 1
2 127237 3 Job Received 22.02.12 07.01.00 3
3 127237 5 Job Started 22.02.12.07.01.00 3
4 127237 5 Jam 22.02.12.07.01.00 2
5 127286 1 Online 22.02.12.07.09.00 1
Status Types
ID Description Weighting
1 Idle 0
2 Error 9
3 Working 5
Expected Output##
ID Status Date
127237 Error 22.02.12 07.01.00
127286 Idle 22.02.12.07.09.00
Sounds like you could use ROW_NUMBER():
SELECT *
FROM (SELECT *,ROW_NUMBER() OVER(PARTITION BY ID ORDER BY Date DESC, Priority, Weighting) 'RowRank'
FROM YourTable a
)sub
WHERE RowRank = 1
Obviously replacing YourTable with the relevant JOIN's
The ROW_NUMBER() function assigns a number to each row. PARTITION BY is optional, but used to start the numbering over for each value in that group, ie: if you PARTITION BY ID then for each unique ID value the numbering will start over at 1. ORDER BY of course is used to define how the counting should go, and is required in the ROW_NUMBER() function.
Updated with your data:
SELECT ObjectID,Description,Date
FROM (SELECT a.*,b.Description,ROW_NUMBER() OVER(PARTITION BY a.ObjectID ORDER BY CONVERT(DATE,LEFT([Date],8),4) DESC, Priority DESC, Weighting DESC) 'RowRank'
FROM Status a
JOIN Status_Types b
ON a.Status = b.ID
)sub
WHERE RowRank = 1
Demo: SQL Fiddle