I have one table t1 like this
A B
1 2020-05-01
1 2020-05-04
1 2020-05-05
1 2020-05-06
2 2020-04-10
and another table t2
A C
1 2020-04-30
5 2020-04-08
and I need out like this:
A B c
1 2020-05-01 2020-04-30
1 2020-05-04 2020-04-30
1 2020-05-05 2020-04-30
1 2020-05-06 2020-04-30
2 2020-04-10 2020-04-08
As you can see i am getting last max date as c from table t2 which less than B
here 2020-04-30 is the max date less than 2020-05-01,04,05 and 06, and for 2020-04-10 the date is 2020-04-08.
I am trying it like this but getting wrong answer:
select t1.*,t2.C, max(C) over (partition by t2.A ) from t1 inner join t2 on t1.A=t2.A and t2.C<t1.B
You could try this approach.
I use CTE(Common Table Expresion) and query the CTE with MAX and GROUP BY
WITH t AS(
SELECT t1.a, t1.b, t2.c
FROM t1, t2
WHERE t1.b > t2.c)
SELECT a, b, MAX(c) AS c
FROM t
GROUP BY a,b;
expected output
+----+-------------+-------------+--+
| a | b | c |
+----+-------------+-------------+--+
| 1 | 2020-05-01 | 2020-04-30 |
| 1 | 2020-05-04 | 2020-04-30 |
| 1 | 2020-05-05 | 2020-04-30 |
| 1 | 2020-05-06 | 2020-04-30 |
| 2 | 2020-04-10 | 2020-04-08 |
+----+-------------+-------------+--+
You can try this:
Select t1.A,t1.B,MAX(t2.B) from t1 t1 join t2 t2 on t1.A=t2.A group by t1.A,t1.B;
Related
I have a table_a with many rows and columns for each timestamp in PostgreSQL 13. I'm trying to find the row where the value in column X is closest to a benchmark value obtained from another table.
This second table has only a single benchmark value for each timestamp. For each timestamp, I need to return most of the columns of table_a. The query below works fine when supplying the value for the benchmark directly.
How can I get the benchmark value from table_b to use in this query?
Simply substituting table_b.benchmark with (SELECT benchmark FROM table_b WHERE table_a.timestamp = table_b.timestamp) results in 'relation "t1" does not exist' error.
Could not figure out a working join either.
table_a:
+-----------------+-----+---------------+
| timestamp | x | other_columns |
+-----------------+-----+---------------+
| 2020-01-01 8:00 | 100 | |
| 2020-01-01 8:00 | 200 | |
| 2020-01-01 8:00 | 300 | |
| 2020-01-01 8:00 | 400 | |
| 2020-01-01 8:00 | 500 | |
| ... | | |
| 2020-01-01 9:00 | 100 | |
| 2020-01-01 9:00 | 200 | |
| 2020-01-01 9:00 | 300 | |
| 2020-01-01 9:00 | 400 | |
| 2020-01-01 9:00 | 500 | |
| ... | | |
+-----------------+-----+---------------+
table_b:
+-----------------+-----------+
| timestamp | benchmark |
+-----------------+-----------+
| 2020-01-01 8:00 | 340 |
| 2020-01-01 9:00 | 380 |
| ... | |
+-----------------+-----------+
Expected result:
+-----------------+-----+
| timestamp | x |
+-----------------+-----+
| 2020-01-01 8:00 | 300 |
| 2020-01-01 9:00 | 400 |
| ... | |
+-----------------+-----+
SQL query:
WITH date_filter AS (
SELECT *
FROM table_a
WHERE timestamp >= {start_date} and timestamp < {end_date}
)
SELECT DISTINCT t1.timestamp, t1.x, t1.etc
FROM date_filter AS t1
INNER JOIN (
SELECT timestamp, MIN(ABS(x - (table_b.benchmark))) AS target_value
FROM t1
GROUP BY timestamp
) AS t2
ON t2.timestamp = t1.timestamp AND t2.target_value = ABS(x - (table_b.benchmark))
ORDER BY timestamp ASC;```
One option uses a lateral join:
select b.timestamp, a.x
from table_b b
cross join lateral (
select a.*
from table_a a
where a.timestamp = b.timestamp
order by abs(a.x - b.benchmark)
limit 1
) a
You can also use distinct on:
select distinct on (b.timestamp) b.timestamp, a.x
from table_b b
inner join table_a a on a.timestamp = b.timestamp
order by b.timestamp, abs(a.x - b.benchmark)
I would suggest a lateral join:
select b.*, a.x
from table_b b left join lateral
(select a.*
from table_a a
where a.timestamp = b.timestamp
order by abs(a.x - b.benchmark)
limit 1
) b
on 1=1;
Table 1 has open times.
id | OpenTime
1 | 2019-12-02 16:52:42.9130000
1 | 2019-12-02 16:55:57.5560000
1 | NULL
1 | 2019-12-02 16:59:09.5640000
1 | 2019-12-02 17:01:35.3510000
2 | 2019-12-02 17:02:55.0270000
2 | 2019-12-02 17:05:41.3930000
2 | 2019-12-02 17:07:41.7870000
Table 2 has close times.
id | CloseTime
1 | NULL
1 | 2019-12-02 16:56:19.2560000
1 | 2019-12-02 16:57:47.5790000
1 | 2019-12-02 16:59:33.5390000
1 | 2019-12-02 17:01:55.6040000
2 | 2019-12-02 17:04:00.7780000
2 | 2019-12-02 17:06:04.4830000
I need to do a DATEDIFF calculation for each open to close time.
It can only be open once at a time, however, we can be missing that event.
We may not yet have the close event.
An OpenTime will normally have a corresponding CloseTime, with CloseTime being greater than OpenTime, but less than the next OpenTime.
id | OpenTime | CloseTime | Datedif
1 | 2019-12-02 16:52:42.9130000 | NULL | NULL
1 | 2019-12-02 16:55:57.5560000 | 2019-12-02 16:56:19.2560000 |
1 | NULL | 2019-12-02 16:57:47.5790000 | NULL
1 | 2019-12-02 16:59:09.5640000 | 2019-12-02 16:59:33.5390000 |
1 | 2019-12-02 17:01:35.3510000 | 2019-12-02 17:01:55.6040000 |
2 | 2019-12-02 17:02:55.0270000 | 2019-12-02 17:04:00.7780000 |
2 | 2019-12-02 17:05:41.3930000 | 2019-12-02 17:06:04.4830000 |
2 | 2019-12-02 17:07:41.7870000 | NULL | NULL
Datediff will just be in seconds DATEDIFF(SECOND,OpenTime,CloseTime).
DROP TABLE IF EXISTS #NEWTABLE;
SELECT
a.ID,
MAX(a.OpenTime) as OpenTime,
MIN(b.CloseTime) as CloseTime ,
DATEDIFF(SECOND, a.OpenTime, b.CloseTime) AS diffSeconds
INTO #NEWTABLE
FROM Table1 a
JOIN Table2 b
ON a.Id= b.Id
WHERE
a.Id = b.ID
and b.CloseTime> = a.OpenTime
Group by a.Id,DATEDIFF(SECOND, a.OpenTime, b.CloseTime)
order by diffSeconds desc
This is not working, but I've tried to make sure that I get the correct corresponding CloseTime to each OpenTime. My code gives 26 rows output for 8 Open and Close events.
you can use LEAD to find the next open time and get the respective record from table2
with cte as(
select id, opentime, lead(opentime,1) over (order by opentime) nextopentime
from table1
where opentime is not null)
select a.id, a.opentime, b.closetime
from cte a
left join table2 b on a.id = b.id and b.closetime > a.opentime and b.closetime < a.nextopentime
order by a.opentime
I have a table 2 transactions let's say table A and B, for some cases i need to transfer row datas from table B to A as new table with several conditions :
The price for the data transferred will follow from the previous data
The same date will not processed into results
When there is no previous data, it will not processed into results
For Example :
-----------Table A------------- ----------Table B----------
product | Date | Price | | Product | Date |
A | 2019-01-01 | 10 | | A | 2018-11-05 |
A | 2019-01-15 | 15 | | A | 2019-01-10 |
A | 2019-01-25 | 20 | | A | 2019-01-12 |
A | 2019-05-01 | 25 | | A | 2019-01-27 |
A | 2019-07-02 | 30 | | B | 2019-02-10 |
B | 2019-02-05 | 40 | | B | 2019-04-22 |
B | 2019-04-22 | 50 | | B | 2019-05-13 |
B | 2019-05-12 | 40 |
Result :
-----------Table C-------------
product | Date | Price |
A | 2019-01-01 | 10 |
A | 2019-01-10 | 10 | *The prices follow the data in the previous date (2019-01-01)
A | 2019-01-12 | 10 | *The prices follow the data in the previous date (2019-01-01)
A | 2019-01-15 | 15 |
A | 2019-01-25 | 20 |
A | 2019-01-27 | 20 | *The prices follow the data in the previous date (2019-01-25)
A | 2019-05-01 | 25 |
A | 2019-07-02 | 30 |
B | 2019-02-05 | 40 |
B | 2019-02-10 | 40 | *The prices follow the data in the previous date (2019-02-05)
B | 2019-04-22 | 50 |
B | 2019-05-12 | 40 |
B | 2019-05-13 | 40 | *The prices follow the data in the previous date (2019-05-12)
NOTE:
For product A in Table B on 2018-11-05 not processed into results because there's no data before that date in the table A for that product.
For product B in Table B on 2019-04-22 not processed into results because the date and product in table A and B are the same (The data is already in table A)
I try not to use looping mechanism because my data reaches millions, but i was too dizzy to think about it.
One way is using group by in a cte and then union:
WITH cte AS(
SELECT b.product,
b.[Date],
MAX(a.[Date]) AS [DateValue]
FROM TableA AS a
INNER JOIN TableB AS b ON a.product = b.product
WHERE a.[Date] <= b.[Date]
GROUP BY b.product, b.[Date]
)
SELECT *
FROM dbo.TableA AS a
UNION
SELECT b.product,
b.[Date],
a.Price
FROM cte AS c
INNER JOIN dbo.TableB AS b ON b.product = c.product AND b.[Date] = c.[Date]
INNER JOIN dbo.TableA AS a ON a.product = c.product AND a.[Date] = c.[DateValue]
ORDER BY product, [Date]
One method uses union all and cross apply:
select ab.product, ab.date, p.price
from ((select a.product, a.date
from a
) union -- intentional to remove duplicates
(select b.product b.date
from b
)
) ab cross apply
(select top (1) a.price
from a
where a.product = ab.product and a.date <= ab.date
order by ab.date desc
) p;
Note that cross apply will eliminate the rows from b that have no price.
If SQL support the ignore nulls option on either last_value() or lag(), this would be more appropriate with a full join:
select coalesce(a.product, b.product) as product,
coalesce(a.date, b.date) as date,
coalesce(a.price,
lag(ignore nulls a.price) over (partition by coalesce(a.product, b.product) order by coalesce(a.date, b.date)) as price
from a full join
b
on a.product = b.product and a.date = b.date;
Alas, SQL Server does not (currently) support that. You can make that work with a bit of effort and additional subqueries.
SQL MERGE is a very powerful tool to perform "CRUD" operation based on some condition...
Please follow the link for more details of this feature.
http://www.sqlservertutorial.net/sql-server-basics/sql-server-merge/
https://www.essentialsql.com/introduction-merge-statement/
Please feel free to ask if you have any doubt.
TelNo | OrderDate | Orders
A | 2017-01-01 | 5
A | 2017-02-02 | 4
A | 2017-07-05 | 6
A | 2017-09-10 | 10
B | 2017-03-01 | 3
B | 2017-04-12 | 6
B | 2017-11-10 | 4
Above is the order table, requirement is to find the sum of 'Orders' for each 'TelNo' within last 6 months from the 'OrderDate' against each record of the table. Below is the expected output;
TelNo | OrderDate | Sum_of_orders
A | 2017-01-01 | 5
A | 2017-02-02 | 9
A | 2017-07-05 | 10
A | 2017-09-10 | 16
B | 2017-03-01 | 3
B | 2017-04-12 | 9
B | 2017-11-10 | 4
I've tried different combinations of CTE and sum(case -- ) over (partition by --) approaches(sql-server-2016), but didn't arrive at a solution. Appreciate if someone can help out in this.
You can use a query like below to get your desired results
See working demo
select t1.TelNo, t1.OrderDate, Sum_of_orders =sum(t2.Orders)
from t t1
join t t2
on t1.TelNo=t2.Telno
and t2.OrderDate between DATEADD(m,-6,t1.OrderDate) and t1.OrderDate
group by t1.TelNo, t1.OrderDate
I would use apply :
select t.TelNo, t.OrderDate, tt.Sum_of_orders
from table t cross apply (
select sum(t1.orders) Sum_of_orders
from table t1
where t1.TelNo = t.TelNo and
t1.OrderDate >= dateadd(mm, -6, t.orderdate) and
t1.OrderDate <= t.OrderDate
) tt;
You can use below query to get desired results:
select mt.TelNo, mt.OrderDate, sum(mt1.orders) from MyTbl mt
left join MyTbl mt1 on mt.TelNo = mt1.TelNo and datediff(day,mt1.OrderDate, mt.OrderDate) <= 180
and mt1.orderdate <= mt.OrderDate
Group by mt.TelNo, mt.OrderDate
order by 1,2
We have the first valuetable table and the query should check if there is
a next younger datetime in the correctiontable table and should add the corrvalue with the corrdatetime.
My problem query:
SELECT * FROM valuetable vt
LEFT JOIN correctiontable corr ON corr.value_id = vt.id WHERE vt.datetime <= corr.corrdatetime
is just delivering the last corrdatetime...
To clarify te results:
Row1 id1 should be NULL as the valuetable datetime is younger than the correction datetime
Row2 id2 should be 01/08/2017 00:00:00 as the datetime in valuetable is older but younger than the 01/12/2017 10:00:00 corrdatetime
Row3 id2 got its correction on 01/12/2017 10:00:00
Row4 id3 is NULL, there is no corrdatetime in correctiontable for it
Thank you all ++
+----------------------------------+
| valuetable |
+----------------------------------+
| id | datetime | value |
+----+---------------------+-------+
| 1 | 22/07/2017 13:00:00 | 123 |
+----+---------------------+-------+
| 2 | 10/08/2017 09:00:00 | 456 |
+----+---------------------+-------+
| 2 | 05/12/2017 20:00:00 | 789 |
+----+---------------------+-------+
| 3 | 11/11/2017 11:11:11 | 012 |
+----+---------------------+-------+
+-------------------------------------------------+
| correctiontable |
+-------------------------------------------------+
| id | value_id | corrdatetime | corrvalue |
+----+----------+---------------------+-----------+
| 1 | 2 | 01/08/2017 00:00:00 | 888 |
+----+----------+---------------------+-----------+
| 2 | 2 | 01/12/2017 10:00:00 | 999 |
+----+----------+---------------------+-----------+
| 3 | 1 | 01/08/2017 20:00:00 | 111 |
+----+----------+---------------------+-----------+
+--------------------------------------------------------------------+
| Result (as it should be) |
+--------------------------------------------------------------------+
| id | datetime | corrdatetime | value | corrvalue |
+----+---------------------+---------------------+-------+-----------+
| 1 | 22/07/2017 13:00:00 | NULL | 123 | NULL |
+----+---------------------+---------------------+-------+-----------+
| 2 | 10/08/2017 09:00:00 | 01/08/2017 00:00:00 | 456 | 888 |
+----+---------------------+---------------------+-------+-----------+
| 2 | 05/12/2017 20:00:00 | 01/12/2017 10:00:00 | 789 | 999 |
+----+---------------------+---------------------+-------+-----------+
| 3 | 11/11/2017 11:11:11 | NULL | 012 | NULL |
+----+---------------------+---------------------+-------+-----------+
Assuming "younger" means "logically less than", this should work for you.
select *
from valuetable a
outer apply (
select top 1 *
from correctiontable y
where y.value_id = a.id
and y.datetime < a.datetime
order by y.datetime desc
) b
Many Thanks to #KindaTechy for delivering me the right path!
I've created two querys, one for MySQL and one for >= Oracle 12.1
For MySQL:
SELECT *
FROM valuetable vt
LEFT JOIN correctiontable ON correctiontable.id
=
(SELECT corr.id
FROM correctiontable corr
WHERE vt.id = corr.value_id
AND vt.datetime <= corr.corrdatetime
ORDER BY datetime DESC
LIMIT 1)
For Oracle:
select *
from valuetable vt
outer apply (
select *
from correctiontable corr
where corr.value_id = vt.id
and corr.corrdatetime < vt.datetime
order by corr.corrdatetime desc
FETCH FIRST 1 ROWS ONLY
) b;
I found a working query, but your id column of valuetable should be unique, because otherwise you get a cross product.
SELECT vt.id, vt.datetime, corr.corrdatetime, vt.value, corr.corrvalue
FROM valuetable vt
LEFT JOIN correctiontable corr
ON corr.value_id = vt.id
AND vt.datetime >= corr.corrdatetime
By changing the date constraint from WHERE-CLAUSE to ON-CLAUSE it will impact only the join and not the result.
A made a sample for you http://sqlfiddle.com/#!9/301a6/4/0
When you need that non-unique id, the query must be improved. And also the test data set.