Select field from recordset that is between dates - sql

Here is an example as it is pretty difficult to explain:
Table one:
| Date | Place ID |
==========================
| 01-Feb-2013 | 1 |
| 21-Jun-2015 | 2 |
Table two:
| Place ID | Date Ranked | Score |
==================================
| 1 | 01-Jan-2012 | 2 |
| 1 | 01-Jan-2014 | 1 |
| 1 | 01-Jan-2010 | 3 |
| 2 | 01-Jan-2016 | 1 |
What I want to happen is with SQL (MS) is when the first record of table one is returned I want whatever the score at that time to be returned from the second table. So in this example the score should be 2 as it is after 01-Jan-2012 but before 01-Jan-2014. And when the second record from table 1 is returned it should return NULL or blank from table 2 as no score existed for that time chosen.
Hope that makes sense!!

In SQL Server, you can use outer apply:
select t1.*, t2.score
from table1 t1 outer apply
(select top 1 t2.*
from table2 t2
where t2.placeid = t1.placeid and
t2.dateranked <= t1.dateranked
order by t2.dateranked desc
) t2;
In this case, you can do the same thing with a correlated subquery as well.

Related

Select two tables side by side

I have two tables filled with two files of which table1 always has one row more than the second.
I want to merge the two tables into one. When I use a right join e.g.
select *
from table2
right join table1 on table1.id = table2.id and table1.eq_nb = table2.eq_nb
I will have the 4 combinations for eq_nb = 25 because it is repeated two times.
But I rather want to stick the columns side by side
To know, I don't have conditions on arrival and depart time of each eq_nb (I can't add something like datediff(second,table1.arrival_time,table2.depart_time) < X )
table1:
id | eq_nb | arival_time
-------------------------------------
1 | 25 | 05:30:15.231
-------------------------------------
2 | 50 | 06:30:15.231
-------------------------------------
3 | 7 | 07:30:15.231
-------------------------------------
1 | 25 | 08:30:15.231
-------------------------------------
5 | 27 | 09:30:15.231
-------------------------------------
table2:
id | eq_nb | depart_time
----------------------------------
1 | 25 | 05:31:15.231
----------------------------------
2 | 50 | 06:31:15.231
----------------------------------
3 | 7 | 07:31:15.231
----------------------------------
1 | 25 | 08:31:15.231
----------------------------------
desired result:
id | eq_nb | arrival_time | depart_time
-------------------------------------------------------
1 | 25 | 05:30:15.231 | 05:31:15.231
-------------------------------------------------------
2 | 50 | 06:30:15.231 | 06:31:15.231
-------------------------------------------------------
3 | 7 | 07:30:15.231 | 07:31:15.231
-------------------------------------------------------
1 | 25 | 08:30:15.231 | 08:31:15.231
--------------------------------------------------------
5 | 27 | 09:30:15.231 | NULL
--------------------------------------------------------
left join should do what you want:
select *
from table1 t1 left join
table2 t2
on t1.id = t2.id and t1.eq_nb = t2.eq_nb;
Given your data, the ids are unique, so there should be no duplication. Note: This is equivalent to your first query; left join is typically easier to follow because all the rows in the first table are in the result set.
Here is a db<>fiddle, illustrating that it works.

How can I subtract two row's values within same column using sql query in access?

(query access)
This is the table structure:
+-----+--------+--------+
| id | name | sub1 |
+-----+--------+--------+
| 1 | ABC | 6.27% |
| 2 | ABC | 7.47% |
| 3 | PQR | 3.39% |
| 4 | PQR | 2.21% |
+-----+--------+--------+
I want to subtract Sub1
Output should be:
+-----+--------+---------+------------------------------------+
| id | name | sub1 | |
+-----+--------+---------+------------------------------------+
| 1 | ABC | 6.27% | 0 First Rec no need Subtract |
| 2 | ABC | 7.47% | 1.2% <=(7.47-6.27) |
| 3 | PQR | 3.39% | 0 First Rec no need Subtract |
| 4 | PQR | 2.21% | -1.18% <=(2.21-3.39) |
+-----+--------+---------+------------------------------------+
Thank you so much.
If you can guarantee consecutive id values, then the following presents an alternative:
select t.*, nz(t.sub1-u.sub1,0) as sub2
from YourTable t left join YourTable u on t.name = u.name and t.id = u.id+1
Change YourTable to the name of your table.
This is painful, but you can do:
select t.*,
(select top 1 t2.sub1
from t as t2
where t2.name = t.name and t2.id < t.id
order by t2.id desc
) as prev_sub1
from t;
This gives the previous value or NULL for the first row. You can just use - for the subtraction.
An index on (name, id) would help a bit with performance. However, if you can upgrade to a better database, you can then just use lag().

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

microsoft sql server - calculate return between every row and the last row

I have a table like the following:
+-------+--------------+
| Value | Date |
+-------+--------------+
| 14 | 10/11/2010 |
| 12 | 10/12/2010 |
| 12 | 10/13/2010 |
| 10 | 10/14/2010 |
| 8 | 10/15/2010 |
| 6 | 10/16/2010 |
| 4 | 10/17/2010 |
| 2 | 10/18/2010 |
+-------+--------------+
I would like to calculate the return (the quotient) between every row and the last row (which is with the latest date). e.g for the row with date "10/16/2010", the result should be 6/2=3
Hence, the resulting table should be
+-------+--------------+
| result| Date |
+-------+--------------+
| 7 | 10/11/2010 |
| 6 | 10/12/2010 |
| 6 | 10/13/2010 |
| 5 | 10/14/2010 |
| 4 | 10/15/2010 |
| 3 | 10/16/2010 |
| 2 | 10/17/2010 |
| 1 | 10/18/2010 |
+-------+--------------+
Is it possible to complete this? thanks you!
You can get the value you want to divide by. Since that's always going to be a single row, you can just use a cross join to join to that and perform your division. SQL Fiddle
with maxdate as
(select max([Date]) as maxdate from table1),
divby as
(select
value as divby
from
table1
inner join maxdate md
on md.maxdate = table1.[date])
select
value / divby
,[date]
from
table1
cross join divby
To break it down a bit, the first CTE (cleverly named maxdate) gets the maximum date for the whole thing. The second CTE (divby) get the value (that you will be dividing by) for that max date. As long as you only get one row back from that, you can safely use a cross join, resulting in each row in your table being divided by that one value.
Another possible solution JOIN the the table to itself.
SQL Fiddle Example
select (t1b.value / t1a.value) as result,
t1b.date from table1 t1a
join table1 t1b on t1a.date = (select max(date) from table1)
Thanks for the fiddle, Andrew! Can be accomplished like this as well if 2008 and above (fiddle: http://sqlfiddle.com/#!3/ecda1/11):
SELECT [Value] / MIN([Value]) OVER () AS result,
[Date]
FROM Table1

Oracle SQL - Making a one to many join one to one based on logic

Sorry for the broad title, I had a hard time coming up with a brief way of describing what I am looking to do. I have two tables (examples below) that I want to join but under a certain condition.
The main table has a field called "DateVal", the second table has a field called "Day". After joining on field "JoinField" I only want to keep rows where the day value in "DateVal" is less than the value of "Day". However, if this criteria is met for multiple values of "Day" I only want it to keep the first instance.
In the second table below, for JoinField "A" there are three rows, for the first I only want it to return times when the day of the month is between 1-10, the second only with the day of the month is between 11-20, and the last 20-31.
A left or inner join will bring back all values, the only way I can think of to get around this is to do a complete join and only return for min("Day"). Can anyone think of a more efficient way?
Thanks in advance.
Table 1
-------------------------------
| ID | JoinField | DateVal |
-------------------------------
| 1 | A | 01/01/2014 |
| 2 | A | 01/16/2014 |
| 3 | B | 05/20/2013 |
-------------------------------
Table 2
--------------------------------
| JoinField | Day | FieldToAdd |
--------------------------------
| A | 10 | A |
| A | 20 | AA |
| A | 31 | AAA |
| B | 15 | B |
| B | 31 | BB |
--------------------------------
Desired Results
--------------------------------------------
| ID | JoinField | DateVal | FieldToAdd |
--------------------------------------------
| 1 | A | 01/01/2014 | A |
| 2 | A | 01/16/2014 | AA |
| 3 | B | 05/20/2014 | BB |
--------------------------------------------
You can do this in a variety of ways. I think a correlated subquery is the easiest way to express it, but unfortunately, the following doesn't work in Oracle:
select t1.*,
(select *
from (select t2.*
from table2 t2
where t2.day < extract(day from t1.dateval)
order by t2.day desc
) t
where rownum = 1
)
from table1 t1;
You can instead do this with join fancy window functions:
select *
from (select t1.*,
row_number() over (partition by t1.id order by t2.day desc) as seqnum
from table1 t1 left outer join
table2 t2
on t2.day < extract(day from t1.dateval)
) t
where seqnum = 1;