SQL Query for Latest Snapshot From Bitemporal Data - sql

Given a table of data with bitemporal modeling, where there are 2 dates: (i) the date that the data applies to, and (ii) the date at which the fact was known.
City Temperature Date As_of_Datetime
---- ----------- ---- --------------
Boston 32 2022/07/01 2022/06/28 13:23:00
Boston 31 2022/07/01 2022/06/29 12:00:00
Miami 81 2022/07/01 2022/06/28 13:23:00
Miami 85 2022/07/01 2022/06/29 12:00:00
What SQL query will give the latest snapshot of the data date based on the As_of_Datetime? e.g.
City Temperature Date
---- ----------- ----
Boston 31 2022/07/01
Miami 85 2022/07/01

select
t1.*
from
temperature_table t1,
(select max(As_of_Datetime) as max_as_of, “City”, “Date” from temperature_table group by “City”, “Date”) t_temp
where
t1.”City” = t_temp.”City” and t1.”Date” = t_temp.”Date” and t1.”As_of_Datetime” = t_temp.”max_as_of”
order by
t1.”City”, t1.”Date”

Related

Check for interchangable column values in SQL

I have 2 tables. The first one contains IDs of certain airports, the second contains flights from one airport to another.
ID Airport
---- ----
12 NYC
23 LOS
21 AMS
54 SFR
33 LSA
from to cost
---- ---- ----
12 23 500
12 23 250
23 12 200
21 23 100
54 12 400
33 21 700
I'd like to return a table where it contains ONLY airports that are interchangeable (NYC -LOS) in that case, with a total cost.
please note that there're identical (from , to) rows with different costs and the desired output needs to aggregate all costs for each unique combination
Desired Output :
airport_1 airport_2 total_cost
---- ---- ----
NYC LOS 950
You can get the result without need of a subquery by using LEAST() and GREATEST() functions along with HAVING clause such as
SELECT MIN(airport) AS airport_1, MAX(airport) AS airport_2, SUM(cost)/2 AS total_cost
FROM flights
JOIN airports
ON id IN ("from" , "to")
GROUP BY LEAST("from","to"), GREATEST("from","to")
HAVING COUNT(DISTINCT "from")*COUNT(DISTINCT "to")=4
where each pair(2) is counted twice(2) -> (2*2=4)
Demo

In Oracle SQL, Add max values (row by row) from another table when other columns of the table are already populated

I have two tables A and B. Table B has 4 columns(ID,NAME,CITY,COUNTRY), 3 columns has values and one column (ID) has NULLS. I want to insert max value from table A column ID to table B where the ID field in B should be in increasing order.
Screenshot
TABLE A
ID NAME
------- -------
231 Bred
134 Mick
133 Tom
233 Helly
232 Kathy
TABLE B
ID NAME CITY COUNTRY
------- ------- ---------- -----------
(NULL) Alex NY USA
(NULL) Jon TOKYO JAPAN
(NULL) Jeff TORONTO CANADA
(NULL) Jerry PARIS FRANCE
(NULL) Vicky LONDON ENGLAND
ID in column in B should be populated as MAX(ID) +1 from table A. The output should look like this:
TABLE B
ID NAME CITY COUNTRY
------ -------- ---------- -----------
234 Alex NY USA
235 Jon TOKYO JAPAN
236 Jeff TORONTO CANADA
237 Jerry PARIS FRANCE
238 Vicky LONDON ENGLAND
Perhaps the simplest method is to create a one-time sequence for the update:
create sequence temp_b_seq;
update b
set id = (select max(id) from a) + temp_b_seq.nextval;
drop sequence temp_b_seq;
You could actually initialize the sequence with the maximum value from a, but that requires dynamic SQL, so this seems like the simplest approach. Oracle should be smart enough to run the subquery only once.

How to list data when a count = 0 for last 3 years?

I am trying to produce a list of branches that haven't made any sales in the last 3 years. I have been able to produce a list of sales that are older than 3 years but not with the added condition of 0 sales in the 3 years prior.
My task is as follows: List all of the branches that have not rented out any tools for more than 3 years.
I think that I have to do a nested subquery but I cannot work out what should go where. Here are the two relevant tables with their descriptions and data values. The only value that should be returned is that for branch 70.
SQL> desc toolorder
Name Null? Type
--------------------------------------------------------- -------- ---
ORDERID NOT NULL VARCHAR2(6)
CUST NOT NULL VARCHAR2(6)
SNAME NOT NULL VARCHAR2(20)
BRANCHID NOT NULL VARCHAR2(6)
TYPE NOT NULL VARCHAR2(15)
TOOLID NOT NULL VARCHAR2(6)
DATEOUT NOT NULL DATE
DUEDATE NOT NULL DATE
SQL> desc branch
Name Null? Type
--------------------------------------------------------------
BRANCHID NOT NULL VARCHAR2(6)
BNAME NOT NULL VARCHAR2(15)
ADDRESS NOT NULL VARCHAR2(25)
TELEPHONE VARCHAR2(11)
MANAGERID VARCHAR2(6)
SQL> select * from toolorder;
ORDERI CUSTOM SNAME BRANCH TYPE TOOLID DATEOUT DUEDATE
------ ------ -------------------- ------ --------------- ------ --------- ---------
000001 000100 smith 10 Adhesive 00042 20-OCT-13 27-NOV-12
000002 000101 jones 10 Guage 00050 13-OCT-12 30-OCT-12
000003 000103 may 10 Generic 00023 21-NOV-12 28-NOV-12
000004 000100 smith 10 Generic 00023 19-NOV-13 28-NOV-13
000005 000104 circus 10 Generic 00023 05-JAN-09 28-JAN-09
000006 000106 hanks 10 Wood 00062 11-APR-10 01-MAY-10
000007 000102 bond 20 Cutting 00073 13-DEC-11 27-DEC-11
000008 000102 bond 20 Guage 00053 13-DEC-11 27-DEC-11
000009 000104 circus 30 Generic 00025 13-DEC-06 28-DEC-06
000010 000104 circus 30 Brickwork 00035 13-DEC-06 28-DEC-06
000011 000105 harris 30 Cutting 00075 13-OCT-13 25-OCT-13
000012 000105 harris 40 Brickwork 00036 13-DEC-11 27-DEC-11
000013 000105 harris 40 Generic 00027 13-DEC-11 27-DEC-11
000014 000105 harris 40 Electric 00006 13-DEC-11 27-DEC-11
000015 000106 hanks 40 Adhesive 00046 13-MAY-11 27-MAY-11
000016 000107 head 50 Adhesive 00047 13-MAR-13 27-MAR-13
000017 000107 head 50 Wood 00018 13-MAR-13 27-MAR-13
000018 000101 jones 50 Guage 00055 06-JAN-13 20-JAN-13
000019 000103 may 60 Brickwork 00039 06-APR-13 20-APR-13
000020 000101 jones 60 Cutting 00080 24-DEC-12 07-JAN-13
000021 000101 circus 70 Cutting 00081 13-AUG-08 27-AUG-08
21 rows selected.
SQL> select * from branch;
BRANCH BNAME ADDRESS TELEPHONE MANAGE
------ --------------- ------------------------- ----------- ------
10 Oxford 18 Oxford Estate 08456325312
20 Greenwood 21 Greenwood Lane 02380282185
30 Weston 36 Weston Road 02380282635
40 Highstreet 12-15 Stafford Highstreet 02380865963
50 Meadow 16 The Meadow Yard 07974296353
60 Port Down 168 Port Down Av 08953164826
70 Red Rd 12-15 Red Road 07948247384
7 rows selected.
Now, running the following query returns the orders that are 3 years old. I need to adjust it (I think) using a nested subqueries, so that it checks there are no sales in the 3 years, but cannot work out how.
SQL> select count(toolorder.orderid) as rentalcount, branch.branchid, branch.bname,
branch.address from toolorder left outer join branch on toolorder.branchid =
branch.branchid where MONTHS_BETWEEN(sysdate, dateout) > 36 group by branch.branchid,
branch.bname, branch.address order by 1 desc;
RENTALCOUNT BRANCH BNAME ADDRESS
----------- ------ --------------- -------------------------
2 30 Weston 36 Weston Road
2 10 Oxford 18 Oxford Estate
1 70 Red Rd 12-15 Red Road
The easiest way to do this is to get the maximum dateout for each branchid and check that it is more than 36 months in the bast:
select b.*
from branch b join
(select branchid, max(dateout) as maxd
from toolorder
group by branchid
) tob
on b.branchid = tob.branchid
where MONTHS_BETWEEN(sysdate, tob.maxd) > 36;
You can use NOT EXISTS to check if something does not match in a correlated sub-query:
SELECT *
FROM branch b
WHERE NOT EXISTS ( SELECT 1
FROM toolorder r
WHERE r.branchid = b.branchid
AND MONTHS_BETWEEN(sysdate, dateout) <= 36 );
From your comment on #Gordon Linoff's answer, it looks like you want to delete matching rows; in which case you can do:
DELETE FROM branch b
WHERE NOT EXISTS ( SELECT 1
FROM toolorder r
WHERE r.branchid = b.branchid
AND MONTHS_BETWEEN(sysdate, dateout) <= 36 );

Access SQL - Select only the last sequence

I have a table with an ID and multiple informative columns. Sometimes however, I can have multiple data for an ID, so I added a column called "Sequence". Here is a shortened example:
ID Sequence Name Tel Date Amount
124 1 Bob 873-4356 2001-02-03 10
124 2 Bob 873-4356 2002-03-12 7
124 3 Bob 873-4351 2006-07-08 24
125 1 John 983-4568 2007-02-01 3
125 2 John 983-4568 2008-02-08 13
126 1 Eric 345-9845 2010-01-01 18
So, I would like to obtain only these lines:
124 3 Bob 873-4351 2006-07-08 24
125 2 John 983-4568 2008-02-08 13
126 1 Eric 345-9845 2010-01-01 18
Anyone could give me a hand on how I could build a SQL query to do this ?
Thanks !
You can calculate the maximum sequence using group by. Then you can use join to get only the maximum in the original data.
Assuming your table is called t:
select t.*
from t join
(select id, MAX(sequence) as maxs
from t
group by id
) tmax
on t.id = tmax.id and
t.sequence = tmax.maxs

Running Totals Results Incorrect

I have a cursor that collects information from a different table and then updates the summary,here is the code snippet that is giving me a headache.
I am trying to update the summary table by input the correct Males and Females information that will add up to the total numbers of patients.
BEGIN
Set #MaleId =154
set #Femaleid =655
if #Category =#MaleId
begin
set #Males = #Value
end
if #Category = #Femaleid
begin
set #CummFemalesOnHaart =#Value
end
Update Stats
set Males =#Malest,Females =#Females
where
Category =#Category and
periodType =#PeriodType AND StartDate =#Startdate and EndDate =#enddate
Problem:
The results are inaccurate
organisation PeriodType StartDate EndDate Deaths Patients Males Females
------------ ---------- ---------- ---------- ------ -------- ----- -------
34 Monthly 2010-04-01 2010-04-30 NULL 6843 896 463
34 Monthly 2010-04-01 2010-04-30 NULL 10041 896 463
34 Monthly 2010-05-01 2010-05-31 NULL 10255 898 463
34 Monthly 2010-05-01 2010-05-31 NULL 7086 898 461
34 Monthly 2010-06-01 2010-06-30 NULL 10344 922 461
36 Monthly 2010-03-01 2010-03-31 NULL 4317 1054 470
36 Monthly 2010-03-01 2010-03-31 NULL 5756 896 470
36 Monthly 2010-04-01 2010-04-30 NULL 4308 896 463
36 Monthly 2010-04-01 2010-04-30 NULL 5783 896 463
The Males and Female should only update single rows that add up to the total number of patiens
e,g
Patients Males Females
-------- ----- -------
41 21 20
Any ideas?
Just to clarify a bit more
/Query Table/
organisation PeriodType StartDate EndDate Males Females
------------ ---------- ---------- ---------- ----- -------
34 Monthly 01-02-2012 01-02-2012 220 205
34 Monthly 01-02-2012 01-02-2012 30 105
/*Update statetement */
Update Stats
set Males =#Malest,Females =#Females
where
--Category =#Category and
periodType =#PeriodType AND StartDate =#Startdate and EndDate =#enddate
Stats Table /Before Input/
organisation PeriodType StartDate EndDate Deaths Patients Males Females
------------ ---------- ---------- ---------- ------ -------- ----- -------
34 Monthly 01-02-2012 01-02-2012 0 425 null null
34 Monthly 01-02-2012 01-02-2012 25 null null null
34 Monthly 01-02-2012 01-02-2012 5 null null null
34 Monthly 01-02-2012 01-02-2012 5 135 null null
/if you look at closely at the rows the period type,startdate,enddate are the same so I don't want the update values to affect any other row besides the ones with the Patients Totals/
Stats Table /* Output */
organisation PeriodType StartDate EndDate Deaths Patients Males Females
------------ ---------- ---------- ---------- ------ -------- ----- -------
34 Monthly 01-02-2012 01-02-2012 0 425 220 205
34 Monthly 01-02-2012 01-02-2012 25 null null null
34 Monthly 01-02-2012 01-02-2012 5 null null null
34 Monthly 01-02-2012 01-02-2012 5 135 30 105
I hope this gives more information
What you are proposing, from what I can see, will always run the risk of having incorrect data assigned. What happens when you have two records, one with patients 500 (males 250 and females 250) and another with patients 500 (but males 300 and females 200)?
There is no clear distinction which record totals to then use, and you'll end up with possible multiple updates with incorrect data.
That being said, I think what you should do is the following.
create a CTE which selects the patients from stats table, and males / females from query table, where patients = (males + females)
Run the update statement on the stats table, using values from the CTE joined on patients total.
This should, as far as I can understand, give a solution to what you're after.
You can read more about CTE's here: MSDN Common Table Expressions
I'm not entirely sure I understand your question... but think this is what you are after?
UPDATE Stats
SET Males = (SELECT COUNT(*) From <queryTable> WHERE Category = #MaleId and periodType =#PeriodType AND StartDate =#Startdate and EndDate =#enddate)
,SET Females = (SELECT COUNT(*) From <queryTable> WHERE Category = #FemaleId and periodType =#PeriodType AND StartDate =#Startdate and EndDate =#enddate)
Hope it helps!
I am not sure I understand the question either. But it sounds like you are saying there can be multiple records having the same periodType, startDate and endDate, but a different number of Patients. You wish to ensure the query only updates records where the total number of Patients matches the total you calculated ie total = #Males + #Females.
If that is correct, add a filter on the Patients value:
UPDATE Stats
SET Males = #Males,
Females = #Females
WHERE Category = #Category
AND periodType = #PeriodType
AND StartDate = #Startdate
AND EndDate = #enddate
AND Patients = (#Males + #Females)
Though as an aside, cursors generally tend to be less efficient than set based alternatives ..