I'm looking for some general guidance on the best solution for a reoccurring SQL query. Basically, I want to create a view of a table which has a lot of nearly identical rows, (except for 1 discerning column called [Status], which can be either 'Closed' or 'Draft').
I want to return distinct data for each [Port], if both 'Closed' and 'Draft' exist, then return only the 'Draft' row data, and if only 'Closed' exists, then return the 'Closed' row data.
Please refer to the attached files for a visual. Any assistance is greatly appreciated! I believe this solution will lend itself well to other practical cases/solutions for me in the future - thank you!
Original Table Data:
Example Output:
Try this,
select c.Port,c.DateAdded,max(Status) as Status
from myTable c
group by c.Port,c.DateAdded
Basically, group the table, and take the highest status code (Closed or Draft)
If both exists, Draft will be returned
Use NOT EXISTS:
SELECT t1.*
FROM tablename t1
WHERE t1.Status = 'Draft'
OR NOT EXISTS (
SELECT 1
FROM tablename t2
WHERE t2.Port = t1.Port AND t1.Status = 'Draft'
)
Or with ROW_NUMBER() window function:
SELECT Port, DateAdded, Status
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY Port ORDER BY CASE WHEN Status = 'Draft' THEN 1 ELSE 2 END) rn
FROM tablename
) t
WHERE rn = 1
A rewording of your requirement is to return just one row per Port, and that Draft rows take precidence over Closed rows.
You don't make clear if they can have different dates though. Such that if one port has two Draft rows or two Closed rows, do you want the earlier dated row, or the later dated row?
The code below presumes the dates can indeed be different, and that your prefer the later dated row.
WITH
sorted AS
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY port ORDER BY status DESC, dateAdded DESC) AS seq_num
FROM
YourTable
)
SELECT
*
FROM
sorted
WHERE
seq_num = 1
If the dates are always identical, MAX(status) with GROUP BY port, dateAdded is easily sufficient.
I'd use a full outer join, and coalesce the results so that the "draft" row is preferred over the "closed" row:
SELECT COALESCE(d.Port, c.Port),
COALESCE(d.DateAdded, c.DateAdded),
COALESCE(d.Status, c.Status)
FROM (SELECT Port, DateAdded, Status
FROM mytable
WHERE Status = 'Draft') d
FULL OUTER JOIN (SELECT Port, DateAdded, Status
FROM mytable
WHERE Status = 'Closed') c ON d.Port = c.Port
Related
I am writing TSQL to eliminate some data in a stored procedure.
The scenario is that there are four data points ID, Recordnumer, OrderDate,RejectDate
The ID can have multiple same or different order date and reject date.
I need to eliminate all the records apart from 1/01/1900 (This is not an actual rejection and a null which is substituted with this value).
However, if no rejection with 1/01/1900 then I should eliminate all records apart from the max of the reject date.
The record number is a roumber that I have done using Row over partition. Please shed a light: The image a particular records and I need to apply this rule on all the records in the table. The expected results are highlighted in yellow for different ID's
Is this what you want?
select t.*
from t
where t.reject_date = '1900-01-01' or
t.reject_date = (select max(t2.reject_date)
from t t2
where t2.id = t.id
);
For each id, this keeps the rows where the reject_date is 1900-01-01 or the reject date is the maximum reject date for that id.
EDIT:
This might be more appropriate:
select t.*
from t
where t.reject_date = (select t2.reject_date
from t t2
where t2.id = t.id
order by (case when t2.reject_date = '1900-01-01' then 1 else 2 end),
t2.reject_date desc
);
Seems you don't need row_number() for this
select id
, OrderDate
, RejectDate
, max(case when RejectDate = '1900-01-01' then '9999-12-31' else RejectDate end) as rSum
from tableA
group by id, OrderDate, RejectDate
I have a table Activity having data like below.It contains multiple rows of CreatedBY like IVR,Raghu and IT.
But I need to get the data only when the first row of CreatedBY='IVR'.
This following query will return firstcreated row for each user (CreatedBy)-
SELECT * FROM
(
SELECT *,
ROW_NUMBER() OVER(PARTITION BY CreatedBy ORDER BY CreatedBy,[Date And Time]) RN
FROM your_table
)A
WHERE RN = 1
I suspect you want the first row per ticket_no. At least, that makes more sense as a query.
If so, in SQL Server, you can use a correlated subquery:
select a.*
from activity a
where a.createdby = 'Raghu' and
a.datetime = (select min(a2.datetime)
from activity a2
where a2.ticket_no = a.ticket_no
);
use exists
select a.*
from table a where createdby='IVR'
and datetime in
(select min(datetime) from table b where a.ticketno=b.ticketno
and createdby='IVR')
I have postgresql data-set as shown below where a app_id may have multiple record. I need to select all the records for each app_id where bool_flag is true and if a app_id has no records with bool_flag value equal true then pick all records with false value for that app.
Here is the link to available data set
data-set
and this is the desired output I am looking for, thanks in advance.
desired output
Here is one method:
select t.*
from t
where t.bool_flag
union all
select t.*
from t
where not t.bool_flag and
not exists (select 1
from t t2
where t2.app_id = t.app_id and t2.bool_flag
);
As the description states, it starts by getting all rows with "true". It then gets the "false" rows where there is no corresponding "true" row.
One way to do it with count window function.
select app_id,created_date,bool_flag
from (select t.*
,count(case when not bool_flag then 1 end) over(partition by app_id) as false_cnt
,count(*) over(partition by app_id) as total
from tbl t
) t
where bool_flag or total=false_cnt
Another way with bool_or.
select t1.*
from (select app_id,bool_or(bool_flag) as bool_res
from tbl
group by app_id
) t
join tbl t1 on t.app_id=t1.app_id
where t.bool_res=t1.bool_flag
I have one table that has "Id", "ParentId", and "CreatedDate". If the row is an original submission, it will have no "ParentId". When an edit is made to an original submission, a new row is created where NewRow."ParentId" = Original."Id". Every new edit made from there on will take the proper "ParentId". This gives a way to see the history of edits.
Now for the query. I rushed together a query that will get all of the latest and unique entries. For example. if I have 3 unique original forms. I only want to see their most recent revision (most recent child) unless they have none, in which case I want the original where "ParentId" IS NULL.
This is the query I am using:
SELECT DISTINCT A.*
FROM "dbo"."customercomplaint" AS A
RIGHT OUTER JOIN "dbo"."customercomplaint" AS B
ON B."parentid" != A."id"
WHERE A."parentid" IS NULL
AND A."id" IS NOT NULL
UNION
SELECT t1.*
FROM "dbo"."customercomplaint" t1
JOIN (SELECT "parentid" AS id,
Max("createddate") AS "CreatedDate"
FROM "dbo"."customercomplaint"
GROUP BY id) t2
ON t1."parentid" = t2.id
AND t1."createddate" = t2."createddate"
This query feels a little sloppy to me and I would like to seek out a better solution. Let me know if any further information is required. I appreciate any and all advice.
You can simplify the query using Row_Number() function.
Below is an example and a working demo
select ID, ParentID, CreatedDate
from (
select ID, ParentID, CreatedDate, row_number() over(partition by isnull(ParentID, ID) order by CreatedDate desc) RowNumber
from CustomerComplaint
) t
where
t.RowNumber = 1
Duplicates in Table 1 are indentifies as follows;
select quote_ref, count (*)
from table 1
group by quote_ref
having count(*) > 1
Now I want the eliminate the duplicates based on the 2 rules below .
Take the entry that has the Status= Complete
If none in complete status then take the one with max([created_date ])
Else Flag to look at ?
Suppose I need a CASE statement with a delete, but not sure how to construct ?
For SQL Server 2005+, you can do the following:
;WITH CTE AS
(
SELECT *,
ROW_NUMBER()
OVER(PARTITION BY quote_ref
ORDER BY CASE WHEN [Status]='COMPLETE' THEN 1 ELSE 2 END,
created_date DESC) RowNum
FROM table1
)
DELETE FROM CTE
WHERE RowNum != 1
In this case, I'm assuming that the row that you don't want to delete is the one with status = 'COMPLETE' or the one with the maximum created_date. If is the other way around, you can simply change the WHERE condition.