Delete rows that contain NULLs if row with ID already exists - sql

I have a table as shown below.
If a product id has been entered into the table with a description, I want to delete all other rows with the same product ids where the description is NULL, leaving only the product id with a description. In the table below, I want to delete ROW_ID = 1 and keep ROW_ID = 2.
Furthermore, if a row is present with product id with a NULL description but no other matching product ids, I want to leave that row in the table. In the table below leaving ROW_ID = 3 as it is.
row_id
product_id
product_description
time_stamp
1
000001
null
2012-12-22 20:00:00
2
000001
item description
2012-12-23 21:00:00
3
000002
null
2012-12-23 21:00:00
The resulting table would look like this:
row_id
product_id
product_description
time_stamp
2
000001
item description
2012-12-23 21:00:00
3
000002
null
2012-12-23 21:00:00

Try something like this assuming the table is named products:
DELETE FROM products as p
WHERE p.product_description is null
AND EXISTS (
SELECT * FROM products as p2 WHERE p2.product_id = p.product_id AND p2.product_description IS NOT NULL
);
The EXISTS operator will return true if the subselect returns greater than 0 rows.

You can try like this:
WITH cte
AS ( SELECT * ,ROW_NUMBER() OVER ( PARTITION BY product_id order by time_stamp desc) as rn
FROM t)
DELETE FROM cte
WHERE rn>1 and cte.product_description is null;
select * from t;
FIDDLE DEMO

Related

How to retrieve historical data based on condition on one row?

I have a table historical_data
ID
Date
column_a
column_b
1
2011-10-01
a
a1
1
2011-11-01
w
w1
1
2011-09-01
a
a1
2
2011-01-12
q
q1
2
2011-02-01
d
d1
3
2011-11-01
s
s1
I need to retrieve the whole history of an id based on the date condition on any 1 row related to that ID.
date>='2011-11-01' should get me
ID
Date
column_a
column_b
1
2011-10-01
a
a1
1
2011-11-01
w
w1
1
2011-09-01
a
a1
3
2011-11-01
s
s1
I am aware you can get this by using a CTE or a subquery like
with selected_id as (
select id from historical_data where date>='2011-11-01'
)
select hd.* from historical_data hd
inner join selected_id si on hd.id = si.id
or
select * from historical_data
where id in (select id from historical_data where date>='2011-11-01')
In both these methods I have to query/scan the table ``historical_data``` twice.
I have indexes on both id and date so it's not a problem right now, but as the table grows this may cause issues.
The table above is a sample table, the table I have is about to touch 1TB in size with upwards of 600M rows.
Is there any way to achieve this by only querying the table once? (I am using Snowflake)
Using QUALIFY:
SELECT *
FROM historical_data
QUALIFY MAX(date) OVER(PARTITION BY id) >= '2011-11-01'::DATE;

find all rows after the recent update using oracle

I tried below query to bring all rows after last Action="UNLOCKED", but ORDER BY is not allowed in subquery it seems.
SELECT *
FROM TABLE
WHERE id >= (SELECT MAX(id)
FROM TABLE
WHERE ACTION='UNLOCKED' AND action_id=123
ORDER BY CREATE_DATE DESC);
Sample data
Id action_id Action ... CREATE_DATE
1 123 ADD 03/18/2018
2 123 Unlocked 03/19/2018
3 123 Updated1 03/19/2018
4 123 Updated2 03/19/2018
5 123 Unlocked 03/20/2018
6 123 Updated3 03/20/2018
7 123 Updated4 03/20/2018
Output should be rows with id 5,6,7. What should i use to get this output
you could use an inner join on subselect for max create_date
select * from TABLE
INNER JOIN (
select max(CREATE_DATE) max_date
from TABLE
where Action = 'Unlocked' ) T on t.max_date = TABLE.CREATE_DATE
You need not order the inner query because it will return only one value. You can do it as follows
SELECT * FROM TABLE WHERE id >= (select max(id) from TABLE where ACTION='UNLOCKED' and action_id=123);

Update a null value cell with an ID and the table is related to 3 others

I have a Table that is joined from other tables. I want to update a null value in this Table by a specific number series. Below is the illustration:
The code for the Table which is called List_Codes
SELECT mlk.MLK_CODE
FROM zpt
LEFT OUTER JOIN mes ON mes.ZPT_ID = zpt.ZPT_ID
LEFT OUTER JOIN zmlk ON zpt.ZPT_ID = zmlk.ZPT_ID
LEFT OUTER JOIN mlk ON zmlk.MLK_ID = mlk.MLK_ID
WHERE zpt.zpt_id IS NOT NULL
and zpt.zpt_meteringcode = '123456'
ORDER BY mes.MES_STATUS DESC
Now I want to update this specific row's mlk.MLK_CODE from null to '789'. I have located this row based on the zpt.zpt_meteringcode. Any suggestions plz?
The tables look like this, and the List_Code Table is the result of the above code
Mlk Table
Mlk_id Mlk_code
1 123
2 456
Zpt Table
Zpt_id Zpt_meteringcode
10 123456
20 987654
30 654321
40 147852
Zmlk Table
Zpt_id Mlk_id
20 1
30 2
List_Code Table
Zpt_id Zpt_meteringcode Mlk_id Mlk_code
10 123456
20 987654 1 123
30 654321 2 456
40 147852
I think you need two inserts and one update statements like this.
INSERT INTO mlk (mlk_code)
VALUES ( '789' ); -- Primary key is generated
.....
INSERT INTO zmlk (zpt_id,
mlk_id)
SELECT (SELECT zpt_id
FROM zpt
WHERE zpt_meteringcode = '123456'),
(SELECT mlk_id
FROM mlk
WHERE mlk_code = '789')
FROM dual;
....
UPDATE list_code
SET ( mlk_id, mlk_code ) = (SELECT mlk_id,
mlk_code
FROM mlk
WHERE mlk_code = '789')
WHERE zpt_meteringcode = '123456';

SQL Server - Select Specific Rows

I have a table with data:
id a_no accountname
1 NULL ac1
1 234 ac2
1 567 ac3
2 NULL ac4
I want to select row with the following criteria:
if same id exist in more than 1 row, then remove the row with a_no=NULL
if id exist in 1 row only, keep that row unchanged
So that the resulting rows should be
id a_no accountname
1 234 ac2
1 567 ac3
2 NULL ac4
How to write the T-SQL query? Thanks.
select * from yourtable
where a_no is not null
union all
select * from yourtable
where id not in
(select id from your table where a_no is not null)
Based on Martinjn query I'd go for:
select * from t
where id not in (
select id from t
where a_no is not null)
or a_no is not null
DELETE FROM yourtable
WHERE id IN (SELECT id FROM yourtable
WHERE NOT a_no IS NULL)
AND a_no IS NULL
Edit: Much simpler
Edit II: Misread your question, you only want to select the rows, not delete them from your table. If so, you can use the following:
SELECT * FROM yourtable
WHERE a_no IS NOT NULL
OR id NOT IN (SELECT id FROM yourtable
WHERE a_no IS NOT NULL)

SQL Select only rows where foreign key has an attribute

I have this table:
| id | Reader id | Book id | Taken date | Return date |
And, for example, 3 rows
id Reader_id Book_id Taken_date Return_date
1 1 1 1999-01-08 NULL
2 2 2 2015-03-09 2015-04-10
3 1 3 2013-01-01 2014-01-01
I need to get the id's of the readers who have returned books, so all the rows with that id in this table need to have Return_date != NULL. In the case above the query is supposed to return only the second row and not return the last row, because the reader from the last row has not returned a book. How to achieve that?
First identify the Reader_id who has to return books
SELECT Reader_id
FROM yourtable
WHERE Return_date IS NULL
Then select the readers from which is not present in above query result
Use NOT IN
SELECT *
FROM yourtable
WHERE Reader_id NOT IN (SELECT Reader_id
FROM yourtable
WHERE Return_date IS NULL)
Or use Not Exists which can handle NULL values from Sub-Query
SELECT *
FROM yourtable a
WHERE NOT EXISTS (SELECT 1
FROM yourtable b
WHERE b.Return_date IS NULL
AND a.Reader_id = b.Reader_id)
You can do this with a left join :
SELECT * FROM YourTable t
LEFT OUTER JOIN YourTable s
ON(t.reader_id = s.reader_id
and s.id <> t.id
and s.Return_date is null)
WHERE s.id is null
AND t.Return_date is not null
Try this...
select
reader_id
from
tablename
where id not in (SELECT id
FROM tablename
WHERE Return_date IS NULL)