SQL query where clause for reporting - sql

Let's say I have this table with the following data:
Service_ID Cust_ID Service_Date Next_Service_Date
-----------------------------------------------------
1 15 2016-01-1 2016-01-31
2 21 2016-01-1 2016-01-31
3 15 2016-01-31 2016-03-1
I need a condition to check if Next_Service_Date is found in Service_Date for each customer not the whole table.
For example customer with id = 15 and Service_ID = 3, you can see Service_Date was made on 2016-01-31
Same as the Next_Service_Date with Service_ID = 1
So output of the query should be
Service_ID Cust_ID Service_Date Next_Service_Date
------------------------------------------------------
2 21 2016-01-1 2016-01-31
I hope I made everything clear.
Note why I want to show record # 2 because that customer has no records in Service_Date that matches the date in Next_Service_Date

If I understand correctly, you want not exists:
select bt.*
from belowtable bt
where not exists (select 1
from belowtable bt2
where bt2.cust_id = bt.cust_id and
(bt2.next_service_date = bt.service_date or
bt2.service_date = bt.next_serice_date
)
);

Edited -- I think I understand your question now -- you want to find all records that should have a next service date scheduled but do not? If so, a combination semi-join and anti-join would do it.
If I'm off the mark, please let me know where I misunderstood.
select
t1.*
from
MyTable t1
where exists (
select null
from MyTable t2
where
t1.Next_Service_Date = t2.Service_Date
)
and not exists (
select null
from MyTable t2
where
t1.Cust_Id = t2.Cust_Id and
t1.Next_Service_Date = t2.Service_Date
)

Related

deleting specific duplicate and original entries in a table based on date

i have a table called "main" which has 4 columns, ID, name, DateID and Sign.
i want to create a query that will delete entries in this table if there is the same ID record in twice within a certain DateID.
i have my where clause that searches the previous 3 weeks
where DateID =((SELECT MAX( DateID)
WHERE DateID < ( SELECT MAX( DateID )-3))
e.g of my dataset im working with:
id
name
DateID
sign
12345
Paul
1915
Up
23658
Danny
1915
Down
37868
Jake
1916
Up
37542
Elle
1917
Up
12345
Paul
1917
Down
87456
John
1918
Up
78563
Luke
1919
Up
23658
Danny
1920
Up
in the case above, both entries for ID 12345 would need to be removed.
however the entries for ID 23658 would need to be kept as the DateID > 3
how would this be possible?
You can use window functions for this.
It's not quite clear, but it seems LAG and conditional COUNT should fit what you need.
DELETE t
FROM (
SELECT *,
CountWithinDate = COUNT(CASE WHEN t.PrevDate >= t.DateId - 3 THEN 1 END) OVER (PARTITION BY t.id)
FROM (
SELECT *,
PrevDate = LAG(t.DateID) OVER (PARTITION BY t.id ORDER BY t.DateID)
FROM YourTable t
) t
) t
WHERE CountWithinDate > 0;
db<>fiddle
Note that you do not need to re-join the table, you can delete directly from the t derived table.
Hope this works:
DELETE FROM test_tbl
WHERE id IN (
SELECT T1.id
FROM test_tbl T1
WHERE EXISTS (SELECT 1 FROM test_tbl T2 WHERE T1.id = T2.id AND ABS(T2.dateid - T1.dateid) < 3 AND T1.dateid <> T2.dateid)
)
In case you need more logic for data processing, I would suggest using Stored Procedure.

id where column has two conditions

I have a table of customers that join and leave a company
ID ActiveFrom ActiveTo
I have for example a where clause that has
where ActiveFrom <= '20170101'
and Activeto < '20170201'
but some times a customer has decided to re-join the company a few days later because of a deal.
example customer:
ID ActiveFrom ActiveTo
1 2000-01-01 2017-01-03
1 2017-01-28 Null
2 2000-01-01 2017-01-06
I want to exclude the customers that do this, from the customers that leave the company but come back
so I want id 2 to be returned only
please help
You can try this.
SELECT * FROM Customer C1
WHERE C1.ActiveFrom <= '20170101'
AND C1.Activeto < '20170201'
AND NOT EXISTS ( SELECT * FROM Customer C2
WHERE C1.ID = C2.ID
AND C2.ActiveTo IS NULL )
You could use a subquery on WHERE statement:
SELECT *
FROM tablename
WHERE (SELECT id FROM tablename WHERE activeTo is null) <> id
GROUP By id
You can find more information here:
https://www.techonthenet.com/sql_server/subqueries.php

Find out the last updated record in my DB using MAX in CASE statement

I have APPLICATIONSTATUSLOG_ID primary key field on my table.
In order to find out the last updated record in my DB and the MAX(APPLICATIONSTATUSLOG_ID) is presumed to be the most recent record.
I tried this code :
SELECT
MAX(CASE WHEN MAX(d.ApplicationStatusLog_ID) = d.ApplicationStatusLog_ID THEN d.ApplicationStatusID END) AS StatusID,
FROM
ApplicationStatusLog d
But I get error:
Msg 130, Level 15, State 1, Line 53 Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
My table looks like
ApplicationID - ApplicationStatusID - ApplicationStatusLogID
10000 17 100
10000 08 101
10000 10 102
10001 06 103
10001 10 104
10002 06 105
10002 07 106
My output should be:
10000 10
10001 10
10002 07
Please help me understand and resolve my problem.
If you want to just find the last updated row, given that it has max value in APPLICATIONSTATUSLOG_ID column. The query would be:
SELECT *
FROM ApplicationStatusLog
WHERE ApplicationStatusLog_ID = (SELECT MAX(ApplicationStatusLog_ID) FROM ApplicationStatusLog )
EDIT
So as you stated in comment, the query for it will be:
DECLARE #statusId INT
SELECT #statusId = STATUSID
FROM ApplicationStatusLog
WHERE ApplicationStatusLog_ID = (SELECT MAX(ApplicationStatusLog_ID) FROM ApplicationStatusLog )
EDIT 2:
The query as per your edit in question will be:
WITH C AS
(
SELECT ApplicationID,ApplicationStatusID,ApplicationStatusLogID, ROW_NUMBER() OVER (PARTITION BY ApplicationID ORDER BY ApplicationStatusLogID DESC) AS ranking
FROM ApplicationStatusLog
)
SELECT ApplicationID,ApplicationStatusID
FROM C
WHERE ranking = 1
You can join same table twice like this:
select IT.JoiningID, JT.MAXAPPLICATIONSTATUSID FROM dbo.[Table] IT
INNER JOIN (
Select JoiningID, MAX (APPLICATIONSTATUSID) MAXAPPLICATIONSTATUSID
FROM dbo.[Table]
GROUP BY JoiningID
) JT ON IT.JoiningID = JT.JoiningID
Now you have MAXAPPLICATIONSTATUSID per ID so you can write what you wand based on MAXAPPLICATIONSTATUSID.
Without full query
SELECT
x.StatusId
...
FROM <Table> a
CROSS APPLY
(
SELECT x.APPLICATIONSTATUSID as StatusId
FROM <Table> x
HAVING MAX(APPLICATIONSTATUSLOG_ID) = a.APPLICATIONSTATUSLOG_ID
GROUP BY x.APPLICATIONSTATUSID
)

update in oracle sql : multiple rows in 1 table

I am new to SQL and I am no good with more advanced queries and functions.
So, I have this 1 table with sales:
id date seller_name buyer_name
---- ------------ ------------- ------------
1 2015-02-02 null Adrian
1 2013-05-02 null John B
1 2007-11-15 null Chris F
2 2014-07-12 null Jane A
2 2011-06-05 null Ted D
2 2010-08-22 null Maryanne A
3 2015-12-02 null Don P
3 2012-11-07 null Chris T
3 2011-10-02 null James O
I would like to update the seller_name for each id, by putting the buyer_name from previous sale as seller_name to newer sale date. For example, for on id 1 John B would then be seller in 2015-02-02 and buyer in 2013-05-02. Does that make sense?
P.S. This is the perfect case, the table is big and the ids are not ordered so neat.
merge into your_table a
using ( select rowid rid,
lead(buyer_name, 1) over (partition by id order by date desc) seller
from your_table
) b
on (a.rowid = b.rid )
when matched then update set a.seller_name= b.seller;
Explanation : Merge into statement performs different operations based on matched or not matched criterias. Here you have to merge into your table, in the using having the new values that you want to take and also the rowid which will be your matching key. The lead function gets the result from the next n rows depending on what number you specify after the comma. After specifying how many rows to jump you also specify on what part to work, which in your case is partitioned by id and ordered by date so you can get the seller, who was the previous buyer. Hope this clears it up a bit.
Either of the below query can be used to perform the desire action
merge into sandeep24nov16_2 table1
using(select rowid r, lag(buyer_name) over (partition by id order by "DATE" asc) update_value from sandeep24nov16_2 ) table2
on (table1.rowid=table2.r)
when matched then update set table1.seller_name=table2.update_value;
or
merge into sandeep24nov16_2 table1
using(select rowid r, lead(buyer_name) over (partition by id order by "DATE" desc) update_value from sandeep24nov16_2 ) table2
on (table1.rowid=table2.r)
when matched then update set table1.seller_name=table2.update_value;
select a.*,
lag(buyer_name, 1) over(partition by id order by sale_date) seller_name
from <your_table> a;

SQL query / data version check

I get stuck with some SQL query which check if dateto from first row is not > than datefrom for second row within same ID.Maybe the easiest way is to present it on example:
ID DATEFROM DATETO PK
1234 20150512 20150518 1
1234 20150514 20150520 2
1234 20150519 null 3
2313 20150512 20150518 4
44341 20150512 null 5
Now, within id 1234 flow is:
1.2015-05-12 -> 2015-05-18
2.2015-05-13 -> 2015-05-20 WRONG
3.2015-05-19 -> null
In this example end date of first row is > than start date for second row.
As output I would like to display PK id ( in this example:2).
Could anyone give me some hints how to approach this? I don't want SQL but just hints. Thanks in advance
You can use a join or correlated subquery for this. I suspect that you want a full overlap comparison:
select t.*
from t
where exists (select 1
from t t2
where t.id = t2.id and
(t2.start_date < t.start_date and
t2.end_date > t.start_date or t2.end_date is null)
);