Update fields with an ID that is driven by date range - sql

I have two tables in SQL:
T1 is laid out as follows:
PrID NapID URN Date
-------------------------------------------
12345 | NULL | 123 | 2019-06-02
23456 | NULL | 456 | 2019-07-03
34567 | NULL | 789 | 2019-07-05
T2 is laid out as follows:
SYSApID PnID StartDate EndDate
-------------------------------------------
54321 | 2 | 2019-06-01 | 2019-06-30
65432 | 3 | 2019-07-01 | 2019-07-31
I'm hoping for a pointer as to how to update the column NapID in table 1, with with the SYSApID from table 2, where it will apply the relevant ID based on where the Date in table 1 falls between the StartDate and EndDate in table2.

a mixture of previous answers
UPDATE
t1
SET
NapID = t2.SYSApID
FROM
t1
JOIN t2 ON t1.date between t2.StartDate and t2.EndDate

You didn't specify your DBMS, so this answer is for SQL SERVER.
update t1
set t1.napID = (select top 1 t2.SYSApID from table2 t2 where t1.[Date] between t2.StartDate and t2.EndDate)
from table1 t1

Try this:
UPDATE t1
SET
t1.napid = t2.sysapid
FROM t1
JOIN t2 ON t2.startdate = CONVERT(VARCHAR(10), DATEADD(month, DATEDIFF(month, 0, date), 0), 120)

You can try below, this works in Oracle :-
update t1
set t1.napID = (select t2.sysappid from t2 where t1.date between t2.start_date and t2.End_date and rownum <2);

Related

pulling rows with a max(column) value but with regards to being smaller than another column in SQL

I have two different data sets but I want to append the columns of one onto the other based on it's date being the max date that is STILL less than the date in the other dataset in SQL.
Example Table 1)
| ID | date | value |
| 05 | 10/13 | ab |
| 10 | 10/15 | sd |
Example Table 2)
| ID2 | date2 | value2 |
| 05 | 10/10 | rf |
| 05 | 10/23 | tx |
| 10 | 10/01 | jk |
| 10 | 10/12 | fr |
| 10 | 10/23 | as |
And the resulting table I want is:
| ID | date | value | date2 | value2 |
| 05 | 10/13 | ab | 10/10 | rf |
| 10 | 10/15 | sd | 10/12 | fr |
When I try to code it, I can't seem to get the correct result. I have tried something like this but I get an error:
select
t1.*
into final
from table1 t1
left join
(select
ID2,
date2,
value2
from
table2
Where max(date2 < date)) AS t2
on t1.ID = t2.ID2;
As noted in the comments, you don't have dates in your sample data. If we pretend you indeed have dates such as those found in this fiddle, then the following could work where CTEs are used.
with max_date as (
select t2.id, max(t2.date) as max_t2_date
from table2 t2
join table1 t1
on t2.id = t1.id
where t2.date < t1.date
group by t2.id
),
max_date_value as (
select t2.id, t2.value, mm.max_t2_date
from table2 t2
join max_date mm
on t2.id = mm.id
and t2.date = mm.max_t2_date
)
select t1.id, t1.date, t1.value, mdv.max_t2_date as date2, mdv.value as value2
from table1 t1
left join max_date_value mdv
on t1.id = mdv.id
Output:
id
date
value
date2
value2
05
2021-10-13T00:00:00.000Z
ab
2021-10-10T00:00:00.000Z
rf
10
2021-10-15T00:00:00.000Z
sd
2021-10-12T00:00:00.000Z
fr
There are likely shorter ways to achieve this but knowing the RDBMS is required. This could at least get you started and play around with different methods.
Assuming that the date and date2 columns are of the type CHAR(5) and stores values like MM/DD, to get the expected results you can use a query like this
WITH t2_rn AS (
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY id2 ORDER BY date2 DESC) AS rn2
FROM table2
WHERE EXISTS (
SELECT 1 FROM table1
WHERE id = id2 AND date > date2
)
)
SELECT
id,
date,
value,
date2,
value2
FROM table1
LEFT JOIN t2_rn ON id = id2 AND rn2 = 1
If you are using SQL Server then you you can use the OUTER APPLY operator, and the query will look like this
SELECT
id,
date,
value,
date2,
value2
FROM table1
OUTER APPLY (
SELECT TOP 1
date2,
value2
FROM table2
WHERE id = id2 AND date > date2 ORDER BY date2 DESC
) t2
Both queries have the same output
id
date
value
date2
value2
5
10/13
ab
10/10
rf
10
10/15
sd
10/12
fr
You can check a working demo with both queries here

How can I pivot two inner joins

I've been tasked to provide the number of orders completed per Employee for every hour that they have worked for throughout the day. The code that I created provide me that requirement but it is an eye-sore and difficult to understand.
To help management in reading my table I am trying to pivot the results.
I've read the Microsoft example but those don't include examples with joins.
Select
t1.id
,t1.EmpName
,datepart(hour,t1.TimeWorked) as theHour
,CAST(t1.TimeWorked as date) as theDay
,t2.Ready
,Sum(t1.Tot_WT) as AccountsWorked
from Transaction as t1
INNER JOIN
(
SELECT
agent,id,Sum(Ready) as Ready,cast(Endtime as DATE) as theDay,
FROM Login_Data
WHERE [READY] <> [NOT_READY]
GROUP BY agent,agentid,cast(Endtime as DATE)
)as t2
on t1.id = t2.id and t2.theDay = cast(t1.TimeWorked as date)
INNER JOIN
(
Select
id, EmpName
From EmployeeRoster
Where Department in ( 'A','B','C','D')
)as t3
on t1.id = t3.id
Where CAST(t1.TimeWorked as date) = cast(GETDATE() as date)
group by t1.id,t1.EmpName,DATEPART(hour,t1.TimeWorked),CAST(t1.TimeWorked as date)
Honestly the Ready column I can remove.
When executing this logic my results display one row for every hour for each agent
+-----+---------+---------+----------+-------+----------------+
| ID | EmpName | thehour | theday | ready | AccountsWorked |
+-----+---------+---------+----------+-------+----------------+
| 123 | Austin | 7 | 08-20-19 | 16001 | 7 |
+-----+---------+---------+----------+-------+----------------+
What I am trying to achieve with the pivot
+-----+---------+---+---+---+----+----+
| ID | EmpName | 7 | 8 | 9 | 10 | 11 |
+-----+---------+---+---+---+----+----+
| 123 | Austin | 7 | 6 | 9 | 2 | 16 |
+-----+---------+---+---+---+----+----+
You can try below query -
SELECT * FROM
( Select t1.id
,t1.EmpName
,datepart(hour,t1.TimeWorked) as theHour
,CAST(t1.TimeWorked as date) as theDay
,t2.Ready
,Sum(t1.Tot_WT) as AccountsWorked
from Transaction as t1
INNER JOIN ( SELECT agent
,id
,Sum(Ready) as Ready
,cast(Endtime as DATE) as theDay
FROM Login_Data
WHERE [READY] <> [NOT_READY]
GROUP BY agent,agentid,cast(Endtime as DATE))as t2 on t1.id = t2.id
and t2.theDay = cast(t1.TimeWorked as date)
INNER JOIN ( Select id
,EmpName
From EmployeeRoster
Where Department in ( 'A','B','C','D'))as t3 on t1.id = t3.id
Where CAST(t1.TimeWorked as date) = cast(GETDATE() as date)
group by t1.id
,t1.EmpName
,DATEPART(hour,t1.TimeWorked)
,CAST(t1.TimeWorked as date)) AS TEMP
PIVOT(
SUM(AccountsWorked) FOR theHour IN (7,8,9,10,11)
) PVT;

Joining rows from two tables

I have two tables Table1 and Table2. I wanted to join the two tables data based on the TIME_STAMP data field
I have tried the below query but I am not able to get the expected result
Table 1
CATEGORY_ID ID TIME_STAMP VALUE
-------------------------------------
1 444 30-Mar-17 XXX
1 444 31-Jul-18 YYY
1 444 15-Jan-19 ZZZ
Table 2
CATEGORY_ID ID TIME_STAMP VALUE
------------------------------------------
2 444 30-Mar-17 10/31/2017
2 444 30-May-18 10/25/2018
2 444 13-Jun-19 10/25/2018
Actual Result:
TIME_STAMP Table 1 VALUE Table 2 value
-------------------------------------------
30-Mar-17 XXX 10/31/2017
31-Jul-18 YYY NULL
15-Jan-19 ZZZ NULL
Query :
SELECT
T1.TIME_STAMP ,
T1.X_VALUE,
T2.X_VALUE
FROM
TABLE1 T1
LEFT OUTER JOIN TABLE2 T2 ON T1.ID = T2.ID
AND
TO_CHAR(T1.TIME_STAMP,'MM/DD/YYYY')
=TO_CHAR(T2.TIME_STAMP,'MM/DD/YYYY')
AND
T2.CATEGORY_ID=2
WHERE
T1.CATEGORY_ID =1 AND T1.ID= 444
Expected Result:
TIME_STAMP Table1 VALUE Table2 VALUE
-----------------------------------------
30-Mar-17 XXX 10/31/2017
30-May-18 NULL 10/25/2018
31-Jul-18 YYY NULL
15-Jan-19 ZZZ NULL
13-Jun-19 NULL 10/25/2018
FULL OUTER JOIN with filtering is tricky. I recommend using a subquery for the filtering criteria:
select coalesce(t1.time_stamp, t2.time_stamp) as time_stamp,
t1.x_value, t2.x_value
from (select t1.*
from table1 t1
where t1.CATEGORY_ID = 1 and T1.ID = 444
) t1 full join
(select t2.*
from table2 t2
where t2.id = 444 and t2.category_id = 2
) t2
on t2.id = t1.id and
trunc(t2.time_stamp) = trunc(t1.time_stamp);
Based on your expected result I think you want to do a FULL OUTER JOIN on the TIME_STAMP column.
You could do something like this.
SELECT COALESCE(t1.time_stamp, t2.time_stamp) AS TIME_STAMP,
t1.value as T1_value,
t2.value as T2_value
FROM table01 t1
FULL OUTER JOIN table02 t2 ON t1.time_stamp = t2.time_stamp
+-------------+-----------+------------+
| TIME_STAMP | T1_value | T2_value |
+-------------+-----------+------------+
| 2017-03-30 | XXX | 10/31/2017 |
| 2018-07-31 | YYY | (null) |
| 2019-01-15 | ZZZ | (null) |
| 2018-05-30 | (null) | 10/25/2018 |
| 2019-06-13 | (null) | 10/25/2018 |
+-------------+-----------+------------+
Note: I have used SQL Server since you haven't mentioned a DBMS.
before you join the two tables with timestamp, you need trunc the timestamp to Date.
like TRUNC("TimeStamp", DATE)
SELECT COALESCE(t1.time_stamp, t2.time_stamp) AS TIME_STAMP,
t1.value as T1_value,
t2.value as T2_value
FROM table01 t1
FULL OUTER JOIN table02 t2
ON trunc(t1.time_stamp, 'DATE') = trunc(t2.time_stamp, 'DATE');

How can I check multiple line for one customer with SQL?

I have a table like this:
id | START_DATE | END_DATE | id_customer
----------------------------------------
1 | 01/05/2016 | 31/05/2016 | 1234
2 | 10/10/2016 | 11/11/2016 | 1234
3 | 11/11/2016 | 15/05/2017 | 1234
4 | 31/12/2016 | 31/06/2017 | 1234
I want select if a START_DATE equal a END_DATE.
For example:
11/11/2016 line id 3 don't equal 31/05/2016 line id 1
11/11/2016 line id 3 equal 11/11/2016 line id 2
11/11/2016 line id 3 don't equal 15/05/2017 line id 3
11/11/2016 line id 3 don't equal 31/06/2017 line id 4
I have try a request like this
SELECT id_cutsomer,START_DATE, END_DATE
FROM TABLE
WHERE START_DATE IN (
SELECT END_DATE FROM DATA_BEAUTY_BOX
)
I want this result:
START_DATE | END_DATE | id_customer
------------------------------------
11/11/2016 | 11/11/2016 | 1234
Can you help me ?
Thanks in advance
I think a self join should suffice
select t1.START_DATE, t2.END_DATE, t1.ID_CUSTOMER
from yourTable t1
join yourTable t2
on t1.START_DATE = t2.END_DATE
If you don't want to mix dates of different customers, you will have to make the join condition stricter
select t1.START_DATE, t2.END_DATE, t1.ID_CUSTOMER
from yourTable t1
join yourTable t2
on t1.START_DATE = t2.END_DATE and
t1.ID_CUSTOMER = t2.ID_CUSTOMER
I would join the tables on Customer ID and then Add the (Start Date = End Date) condition on the WHERE clause. (although you could do them both on the JOIN)
SELECT t1.START_DATE, t2.END_Date, t1.id_customer
FROM MyTable t1
INNER JOIN MyTable t2
ON t1.id_customer = t2.id_customer
WHERE t1.START_DATE = t2.END_Date

Getting all the current effective records from a ORACLE table

I have two tables in oracle database
Table 1 say table1 with fields (id, name)
Records e.g.
###############
id | name
1 | Chair
2 | Table
3 | Bed
###############
and Table 2 say table2 with fields (id, table1_id, date, price)
##############################
id |table1_id| date | price
1 | 1 | 2013-09-09 | 500
2 | 1 | 2013-08-09 | 300
3 | 2 | 2013-09-09 | 5100
4 | 2 | 2013-08-09 | 5000
5 | 3 | 2013-09-09 | 10500
################################
What I want to achieve is to retrieve all the latest price of items from table 2
Result of SQL should be like
##############################
id |table1_id| date | price
1 | 1 | 2013-09-09 | 500
3 | 2 | 2013-09-09 | 5100
5 | 3 | 2013-09-09 | 10500
################################
I am able to run in mysql by following query
SELECT t2.id, t1.id, t1.name, t2.date, t2.price
FROM table1 t1 JOIN table2 t2
ON (t1.id = t2.table1_id
AND t2.id = (
SELECT id
FROM table2
WHERE table1_id = t1.id
ORDER BY table2.date DESC
LIMIT 1
));
but it's not working in ORACLE, Here i Need a query which can run on both server with minor modification
You may try this (shoud work in both MySQL and Oracle):
select t2.id, t2.table1_id, t2.dat, t2.price
from table1 t1 join table2 t2 on (t1.id = t2.table1_id)
join (select table1_id, max(dat) max_date
from table2 group by table1_id) tmax
on (tmax.table1_id = t2.table1_id and tmax.max_date = t2.dat);
This query may return several rows for the same table1_id and date if there are several prices in table2, like this:
##############################
id |table1_id| date | price
1 | 1 | 2013-09-09 | 500
2 | 1 | 2013-09-09 | 300
It's possible to change the query to retrieve only 1 row for each table1_id, but there should be some additional requirements (which row to choose in the above example)
if it doesn't matter then you may try this:
select max(t2.id) as id, t2.table1_id, t2.dat, max(t2.price) as price
from table1 t1 join table2 t2 on (t1.id = t2.table1_id)
join (select table1_id, max(dat) max_date
from table2 group by table1_id) tmax
on (tmax.table1_id = t2.table1_id and tmax.max_date = t2.dat)
group by t2.table1_id, t2.dat;
You can try this using GROUP BY instead, since you're not retrieving the product name from table1 except the product id (which is already in table2)
SELECT id,table1_id,max(date),price
FROM table2
GROUP BY id,table1_id,price
this is what you want :
select t2.id,t2.table1_id,t1.name,t2.pricedate,t2.price
from table1 t1
join
(
select id,table1_id, pricedate,price, row_number() over (partition by table1_id order by pricedate desc) rn
from table2
) t2
on t1.id = t2.table1_id
where t2.rn = 1