Checking if time is within a set of start and end times - hive

I am trying to figure out if a certain time lies with a set of start and end times for every id between 2 different tables
For example there are 2 tables Table_A and Table_B
Table A schema Looks like this
ID | timestamp | status - This holds information for every unit of time (say every minute)
Table B schema looks like this
ID | Start_timestamp | End_timestamp - However there are multiple entries for every ID for the same date.
I want to figure out if timestamp in Table_A lies between any of the start_timestamp or end_timestamps in Table_B
Expected results
Table_A
ID | timestamp | status
1 | 300 | ABC
1 | 600 | ABC
1 | 900 | ABC
1 | 1200 | DEF
...
Table_B
ID | Start_timestamp | End_timestamp
1 | 100 | 400
1 | 700 | 1000
Output
ID | timestamp | status | Flag
1 | 300 | ABC | True
1 | 600 | ABC | False
1 | 900 | ABC | True
1 | 1200 | DEF | False

This can be done with a left join and conditional aggregation.
select a.id,a.timestamp,a.status
,max(case when a.timestamp between b.start_time and b.end_time then 'True' else 'False' end) as t_f_flag
from tblA a
left join tblB b on a.id = b.id
group by a.id,a.timestamp,a.status

Related

How to fetch record from Table A which has not any approved status true on Table B

I have three table A , B and C and it structure is shown below
Table A
----------------------------
| id | Text_message_to_show|
----------------------------
| 1 | first demo message |
----------------------------
| 2 | second demo message |
----------------------------
Table B
------------------------------------
| id | request_id | approved_status |
------------------------------------
| 101 | 1 | 2 |
------------------------------------
| 102 | 1 | 1 |
------------------------------------
| 103 | 2 | 2 |
------------------------------------
| 104 | 2 | 2 |
------------------------------------
Table c
------------------------------------
| id | request_id | approved_status |
------------------------------------
| 501 | 1 | 2 |
------------------------------------
| 502 | 2 | 1 |
------------------------------------
Table B and Table C has foreign key request_id column which is reference id column of table A.Table Table A-> Table B has one to many relaionship and Table A->Table C has one to one relationship Now I have question is how to wrie sql query such that to fetch Table A record where no approved_status for request_id should be 2 in Table B And also Table C approved_status should not be 2
You can use not exists like following.
select *
from tablea ta
where not exists (
select 1
from tableb tb
where ta.id = tb.request_id
AND tb.approved_status = 2
)
You can use left join as follows:
Select a.*
From a
Left Join b on a.id = b.request_id and b.approved_status = 2
Left join c on a.id = c.request_id and c.approved_status = 2
Where coalesce(b.id,c.id) is null
select * from tablea ta
where not exists
(
select id from tableb tb where ta.id=tb.request_d and tb.approved_status = 2
)
This may help you out.

Postgres SQL query to get the first row of distinct id

channels table
id | name
------------
1 | ABC
2 | XYZ
3 | MNO
4 | ASD
user_channels table
user_id | channel_id
----------------------
555 | 1
666 | 1
777 | 1
555 | 2
888 | 2
999 | 3
555 | 3
user_chats table
id | created_at | channel_id | content
---------------------------------------
2 | time 1 | 1 | Hello
3 | time 2 | 1 | Hi
4 | time 3 | 2 | Good day
5 | time 4 | 2 | Morning
I have these 3 tables in postgres SQL,
I want to write a sql query to get user_channels by user_id and it's latest message only (time 1 is oldest message) from user_chats table. How can I do that?
For example, for user_id = 555, the query should return
channel_id | content | created_at
---------------------------------------
1 | Hi | time 2
2 | Morning | time 4
3 | Null | Null
Use distinct on:
select distinct on (a.channel_id) a.*
from user_chats a
inner join user_channels l on l.channel_id = a.channel_id
where l.user_id = 555
order by a.channel_id, a.createt_at desc
If you want this for all users at once:
select distinct on (l.user_id, a.channel_id) l.user_id, a.*
from user_chats a
inner join user_channels l on l.channel_id = a.channel_id
order by l.user_id, a.channel_id, a.createt_at desc
You can use distinct on:
select distinct on (c.channel_id) c.channel_id, uc.content, uc.created_at
from user_channels c left join
user_chats uc
on uc.channel_id = c.channel_id
where c.user_id = ?
order by c.idchannel_id, uc.created_at desc;

How do I do an Oracle SQL update from select in a specific order?

I have a table with old values (some null) and new values for various attributes, all inserted at different add times throughout the months. I'm trying to update a second table with records with business month end dates. Right now, these records only contain the most recent new values for all month end dates. The goal is to create historical data by updating the previous month end values with the old values from the first table. I am a beginner and was able to come up with a query to update on one object where there was one entry from the first table. Now I am trying to expand the query to include multiple objects, with possible, multiple old values within the same month. I tried to use "order by" (since I need to make updates for a month in ascending order so it gets the latest value) but read that doesn't work with update statements without a subquery. So I tried my hand at making a more complicated query, without success. I am getting the following error: single-row subquery returns more than one row. Thanks!
TableA:
| ID | TYPE | OLD_VALUE | NEW_VALUE | ADD_TIME|
-----------------------------------------------
| 1 | A | 2 | 3 | 1/11/2019 8:00:00am |
| 1 | B | 3 | 4 | 12/10/2018 8:00:00am|
| 1 | B | 4 | 5 | 12/11/2018 8:00:00am|
| 2 | A | 5 | 1 | 12/5/2018 08:00:00am|
| 2 | A | 1 | 2 | 12/5/2019 09:00:00am|
| 2 | A | 2 | 3 | 12/5/2019 10:00:00am|
| 2 | B | 1 | 2 | 12/5/2019 10:00:00am|
TableB
| ID | MONTH_END | TYPE_A | TYPE_B |
-----------------------------------
| 1 | 1/31/19 | 3 | 5 |
| 1 | 12/31/18 | 3 | 5 |
| 1 | 11/30/18 | 3 | 5 |
| 2 | 12/31/18 | 3 | 2 |
| 2 | 11/30/18 | 3 | 2 |
Desired Output for TableB
| ID | MONTH_END | TYPE_A | TYPE_B |
-----------------------------------
| 1 | 1/31/19 | 3 | 5 |
| 1 | 12/31/18 | 2 | 5 |
| 1 | 11/30/18 | 2 | 3 |
| 2 | 12/31/18 | 3 | 2 |
| 2 | 11/30/18 | 5 | 2 |
My Query for Type A (Which I plan to adapt for Type B and execute as well for the desired output)
update TableB B
set b.type_a =
(
with aa as
(
select id, nvl(old_value, new_value) typea, add_time
from TableA
where type = 'A'
order by id, add_time ascending
)
select typea
from aa
where aa.id = b.id
and b.month_end <= aa.add_tm
)
where exists
(
with aa as
(
select id, nvl(old_value, new_value) typea, add_time
from TableA
where type = 'A'
order by id, add_time ascending
)
select typea
from aa
where aa.id = b.id
and b.month_end <= aa.add_tm
)
Kudo's for giving example input data and desired output. I found your question a bit confusing so let me rephrase to "Provide the last type a value from table a that is in the same month as the month end.
By matching on type and date of entry, we can get your answer. The "ROWNUM=1" is to limit result set to a single entry in case there is more than one row with the same add_time. This SQL is still a mess, maybe someone else can come up with a better one.
UPDATE tableb b
SET b.typea =
(SELECT old_value
FROM tablea a
WHERE LAST_DAY( TRUNC( a.add_time ) ) = b.month_end
AND TYPE = 'A'
AND add_time =
(SELECT MAX( add_time )
FROM tablea
WHERE TYPE = 'A' AND LAST_DAY( TRUNC( a.add_time ) ) = b.month_end)
AND ROWNUM = 1)
WHERE EXISTS
(SELECT old_value
FROM tablea a
WHERE LAST_DAY( TRUNC( a.add_time ) ) = b.month_end AND TYPE = 'A');

SQL : Comparing multiple values in one table with a single value in another Table

I have two tables Table 1 and Table 2
Table 1:
-------------------------------
| Ser | StartDate | Activity |
-------------------------------
| 1 | 2002-10-13 | 1 |
| 1 | 2002-10-13 | 2 |
| 1 | 2007-09-04 | 3 |
Table 2:
------------------------
|Ser|DateOfRegistration|
------------------------
| 1 | 2002-10-12 |
| 1 | 2007-09-02 |
Now, the result that I want is such that for Activity 1 and 2 the Date of registration should be before the Start Date and difference between the dates must be the least. Similarly, for Activity 3, the date of registration for Activity 3 should be before the start date. The result should look like this.
Table 3:
--------------------------------------------
|Ser|StartDate |DateofRegistration|Activity|
--------------------------------------------
| 1 |2002-10-13| 2002-10-12 | 1 |
| 1 |2002-10-13| 2002-10-12 | 2 |
| 1 |2002-09-04| 2002-09-02 | 3 |
How can I join Table 1 and 2 to get Table 3?
You can use outer apply:
select t1.*, t2.dateofregistration
from table1 t1 outer apply
(select top (1) t2.*
from table2 t2
where t2.ser = t1.ser and t2.dateofregistration < t1.startdate
order by t2.dateofregistration desc
) t2

Best Hive SQL query for this

i have 2 table something like this. i'm running a hive query and windows function seems pretty limited in hive.
Table dept
id | name |
1 | a |
2 | b |
3 | c |
4 | d |
Table time (build with heavy load query so it's make a very slow process if i need to join to another newly created table time.)
id | date | first | last |
1 | 1992-01-01 | 1 | 1 |
2 | 1993-02-02 | 1 | 2 |
2 | 1993-03-03 | 2 | 1 |
3 | 1993-01-01 | 1 | 3 |
3 | 1994-01-01 | 2 | 2 |
3 | 1995-01-01 | 3 | 1 |
i need to retrieve something like this :
SELECT d.id,d.name,
t.date AS firstdate,
td.date AS lastdate
FROM dbo.dept d LEFT JOIN dbo.time t ON d.id=t.id AND t.first=1
LEFT JOIN time td ON d.id=td.id AND td.last=1
How the most optimized answer ?
GROUP BY operation that will be done in a single map-reduce job
select id
,max(name) as name
,max(case when first = 1 then `date` end) as firstdate
,max(case when last = 1 then `date` end) as lastdate
from (select id
,null as name
,`date`
,first
,last
from time
where first = 1
or last = 1
union all
select id
,name
,null as `date`
,null as first
,null as last
from dept
) t
group by id
;
+----+------+------------+------------+
| id | name | firstdate | lastdate |
+----+------+------------+------------+
| 1 | a | 1992-01-01 | 1992-01-01 |
| 2 | b | 1993-02-02 | 1993-03-03 |
| 3 | c | 1993-01-01 | 1995-01-01 |
| 4 | d | (null) | (null) |
+----+------+------------+------------+
select d.id
,max(d.name) as name
,max(case when t.first = 1 then t.date end) as 'firstdate'
,max(case when t.last = 1 then t.date end) as 'lastdate'
from dept d left join
time t on d.id = t.id
where t.first = 1 or t.last = 1
group by d.id