SQL Server - How can I select the first row with the word "Rehired" that shows up after the last row with the word "Quit" - sql-server-2000

Date..............Comment1............................Comment2
20041206.....Address change from/to:........616 Barry Road Apt
20050314.....Rehired on Mar 14/05............Rehired on Mar 14/05
20051117.....Terminated on Nov17/05.......Shortage of Work
20060131.....Address change from/to:........616 Barry Road Apt
20060410.....Rehired on Apr 10/06 ............Pay Rate change
20060419.....Vac. pay owing: from..............changed by
20060531.....Terminated on May31/06........Quit
20070208.....Address change from/to:........11 Bettley Court
20080921.....Rehired on Sep 21/08............Pay Rate change <== this row
20080925.....Vac. pay owing:.....................from
20090215.....Pay Rate change...................0.00
20090712.....Pay Rate change...................0.000
I want to end up with the Date (20080921) from the indicated record .

Something like
SELECT TOP 1 *
FROM YourTable
WHERE Date > (SELECT TOP 1 Date
FROM YourTable
WHERE ( Comment1 LIKE '%Quit%'
OR Comment2 LIKE '%Quit%' )
ORDER BY Date DESC)
AND ( Comment1 LIKE '%Rehired%'
OR Comment2 LIKE '%Rehired%' )
ORDER BY Date

A little rough, but:
SELECT t2.DATE
FROM TABLE t1 INNER JOIN
TABLE t2 on t1.Date < t2.Date LEFT OUTER JOIN
TABLE t3 on t1.Date < t3.Date AND t3.Date < t2.Date AND t3.Comment1 LIKE 'Rehired%' LEFT OUTER JOIN
TABLE t4 on t4.Date > t1.Date and t4.Comment2 = 'Quit'
WHERE t1.Comment2 = 'Quit'
AND t2.Comment1 like 'Rehired%'
AND t3.Date = null
AND t4.Date = null
t1 is your quit record and t2 is your rehired record. t3 ensures no other rehired occurs between t1 and t2, and t4 ensures no other quit occurs after t1. Therefore, t2 is the firstmost rehired after the lastmost quit.

Date format could be tricky, but try like this.
declare #LastDate datetime
set #LastDate='2008/09/21'
select date,comment1,comment2 from your table
where cast(date as datetime)>=#LastDate
order by date

Related

How to select value in a table based on date range that may change

I can't seem to find a question that specifically addresses the requirements of what I'm trying to do here, but apologies if this isn't the case.
I have an example table:
type|start_date|end_date |cost|
bananas|2019-01-01|2019-01-31|100
bananas|2019-02-01|2019-02-28|95
juice |null |null |55
And so on. The point of the table is that the 'food' or whatever else, can be a different price based on a different time range, however there are some items e.g. juice, that don't get affected when the date changes (i.e they stay constant).
In another table, I want to lookup a value based on the date range in the table above.
For example:
customerId|transaction_date|item |quantity|
abc123 |2019-01-25 |bananas|4
abc126 |2019-02-06 |bananas|4
abc128 |2019-02-09 |juice |1
So the first two customers bought bananas, but one in January and one in February.
Then another customer bought juice.
How can I return the correct corresponding cost based on my other table.
I have tried to do where date is BETWEEN the two, but this alienates any other dates that don't exist in the pricing table.
I've also tried to use CASE to approach this, but to no avail.
What would be the best approach to this?
I would expect the result to yield a joined table with the following:
customerId|transaction_date|item |quantity|cost|
abc123 |2019-01-25 |bananas|4 |100
abc126 |2019-02-06 |bananas|4 |95
abc128 |2019-02-09 |juice |1 |55
Where cost column is joined by the criteria above?
You could use ISNULL on the left join.
SELECT P.*, C.cost
FROM Purchases P
LEFT JOIN Product_Costs C ON P.item = C.type
AND P.transaction_date >= ISNULL(C.start_date, P.transaction_date)
AND P.transaction_date <= ISNULL(C.end_date, P.transaction_date);
Modified Nick's fiddle: http://sqlfiddle.com/#!18/e366b/6
You can use a correlated subquery:
select t2.*,
(select t1.cost
from table1 t1
where t1.type = t2.type and
t2.transaction_date >= t1.start_date and
t2.transaction_date <= t1.end_date
) as cost
from table2 t2;
Or, you can use a left join:
select t2.*, t1.cost
from table2 t2 left join
table1 t1
on t1.type = t2.type and
t2.transaction_date >= t1.start_date and
t2.transaction_date <= t1.end_date ;
EDIT:
You can handle NULL values with OR:
select t2.*, t1.cost
from table2 t2 left join
table1 t1
on t1.type = t2.type and
(t2.transaction_date >= t1.start_date or
t1.start_date is null
) and
(t2.transaction_date <= t1.end_date or
t1.end_date is null
);
You could use an outer apply:
SELECT p.*,
c.cost
FROM Purchases AS p
OUTER APPLY (
SELECT TOP 1 c.cost
FROM Product_Costs AS c
WHERE p.transaction_date BETWEEN c.start_date AND c.end_date
AND c.type = p.Item
) AS c;
I've created a Sql Fiddle using your example data: http://sqlfiddle.com/#!18/e366b/2/0

Does anyone know how to SQL this query in Google Big Query?

I have a first database in the following format:
transaction_time id
2009-12-12 12:12 12345
2009-12-12 12:13 12346
... ...
The second database is in the following format:
id name
12345 abc
12346 bcd
... ...
I would like to write a query in Standard SQL for Google Big Query to count all occurrences of the same id on the same date and then return the name for the occurence (as in an Excel VLOOKUP).
I think it would be something along the lines of:
SELECT
DATETIME "2008-12-25 15:30:00" as original,
DATETIME_TRUNC(DATETIME "2008-12-25 15:30:00", DAY) as truncated
select t2.name, t1.id
from table1 t1 join
table2 t2
on t2.id = t1.request_time
Can anybody confirm? Or is there a GROUP BY function in Standard SQL for Big Query? I couldn't seem to find one!
Thanks very much!
Is this what you want?
select date(t1.request_time) as dte, count(*)
from table1 t1 join
table2 t2
on t2.id = t1.request_time
group by dte
order by dte;
Of course Standard SQL supports GROUP BY -- it is a very functional database from a querying perspective.
Or this?
select t2.name, count(*)
from table1 t1 join
table2 t2
on t2.id = t1.request_time
where date(t1.request_date) = date('2008-12-25')
group by t2.name;

Subselect in the ON clause

Please dont bash me if there are already answers for this question, but I found none.
Basically I want to make a subselect in the ON clause of a Left join to get the newest entry in a timeframe.
(start and endtime are timestamps, hardcoded, in local variables or host variables in a Cobol program) to simplify I used integers in that question.
Select * from table1 as t1
left join table2 as t2 on
t1.primary = t2.secondary
and t2.timestamp = (
select max(t2a.timestamp) from table2 as t2a
where t2.primary = t2a.primary
and t2a.timestamp > starttime
and t2a.timestamp < endtime
)
Now this does not work, I get the following error:
AN ON CLAUSE IS INVALID. SQLCODE=-338
Because (see the docs)
The ON clause cannot contain a subquery.
Now what we can do to surround that is instead of joining table2 to join a already delimited subquery. But that surrounds the query optimizer what literally kills the performance:
Select * from table1 as t1
left join (
select t2a.secondary from table2 as t2a
where t2a.timestamp = (
select max(t2b.timestamp)
from table2 as t2b
where t2a.primary = t2b.primary
and t2b.timestamp > starttime
and t2b.timestamp < endtime
)
)as t2
on t1.primary = t2.secondary
Any idea how to slove this?
Example data table1:
t1.primary
1
2
3
Example data table2:
t2.primary t2.secondary t2.timestamp
1 1 4
2 1 5
3 1 10
4 2 4
5 2 5
Variables:
starttime = 3
endtime = 6
Expected result:
t1.primary t2.primary t2.secondary t2.timestamp
1 2 1 5 --Leftjoined the newest entry in range
2 5 2 5
3 NULL NULL NULL
This should work
select *
from table1 t1
left join (
select t2.primary, t2.secondary, t2.timestamp,
row_number() over (partition by t2.secondary order by t2.timestamp desc) rn
from table2 t2
where t2.timestamp between starttime and endtime
) t on t1.primary = t.secondary and t.rn = 1
If you have an index table2(timestamp, secondary, primary) or at least table2(timestamp, secondary) then it should run really fast. Without the indexes, it still works with quite good performance, since it leads to one sequential scan of the tables.
something like this. Just typed in before lunch so don't bash me if it doesn't work.
select * from table1 a left join
(select t2b.primary, max(t2b.timestamp) mxts
from table2 t2b
group by t2b.primary
) as b on a.primary = b.primary
left join table2 on b.primary = table2.secondary and
table2.timestamp = mxts and table2.timestamp between mystartts and myendts
NOte: Don't assume timestamps are unique and can be used to extract the last entry from a table because this will undobtly fraile.

SQL Join based on dates- Table2.Date=Next date after Table1.Date

I have two seperate tables which I want to join based on Dates. However, I don't want the dates in the tables to be equal to one another I want the date (and accompanying value) from one table to be joined with the next date available after that date in the second table.
I've put an example of the problem below:
Table 1:
Date Value
2015-04-13 A
2015-04-10 B
2015-04-09 C
2015-04-08 D
Table 2:
Date Value
2015-04-13 E
2015-04-10 F
2015-04-09 G
2015-04-08 H
Desired Output Table:
Table1.Date Table2.Date Table1.Value Table2.Value
2015-04-10 2015-04-13 B E
2015-04-09 2015-04-10 C F
2015-04-08 2015-04-09 D G
I'm at a bit of an ends of where to even get going with this, hence the lack of my current SQL starting point!
Hopefully that is clear. I found this related question that comes close but I get lost on incorporating this into a join statment!!
SQL - Select next date query
Any help is much appreciated!
M.
EDIT- There is a consideration that is important in that the day will not always be simply 1 day later. They need to find the next day available, which was in the original question but Ive update my example to reflect this.
Since you want the next available date, and that might not necessarily be the following date (eg. date + 1) you'll want to use a correlated subquery with either min or top 1.
This will give you the desired output:
;WITH src AS (
SELECT
Date,
NextDate = (SELECT MIN(Date) FROM Table2 WHERE Date > t1.Date)
FROM table1 t1
)
SELECT src.Date, src.NextDate, t1.Value, t2.Value
FROM src
JOIN Table1 t1 ON src.Date = t1.Date
JOIN Table2 t2 ON src.NextDate = t2.Date
WHERE src.NextDate IS NOT NULL
ORDER BY src.Date DESC
Sample SQL Fiddle
try this
select [Table 1].Date,[Table 1].Value,[Table 2].date,[Table 2].Value
from [Table 1]
join [Table 1]
on dateadd(dd,1,[Table 1].date) = [Table 2].date
i'd go with an outer apply:
SELECT t1.*, t2.*
FROM Table1 t1
CROSS APPLY (
SELECT TOP 1 *
FROM Table2 t2
WHERE t2.Date > t1.Date
ORDER BY t2.Date) t2
ORDER BY t1.Date DESC

SQL - Query to return result

There is a table with Columns as below:
Id : long autoincrement;
timestamp:long;
price:long
Timestamp is given as a unix_time in ms.
Question: what is the average time difference between the records ?
First thought is a sub-query grabbing the record immediately previous:
SELECT timestamp -
(select top 1 timestamp from Table T1 where T1.Id < Table.Id order by Id desc)
FROM Table
Then you can take the average of that:
SELECT AVG(delta)
from (SELECT timestamp -
(select top 1 timestamp from Table T1 where T1.Id < Table.Id order by Id desc) as delta
FROM Table) T
There will probably need to be some handling of the null that results for the first row, but I haven't tested to be sure.
In SQL Server, you could write something like that to get that information:
SELECT
t1.ID, t2.ID,
DATEDIFF(MILLISECOND, t2.PriceTime, test2.PriceTime)
FROM table t1
INNER JOIN table t2 ON t2.ID = t1.ID-1
WHERE t1.ID > (SELECT MIN(ID) FROM table)
and if you're only interested in the AVG across all entries, you could use:
SELECT
AVG(DATEDIFF(MILLISECOND, t2.PriceTime, test2.PriceTime))
FROM table t1
INNER JOIN table t2 ON t2.ID = t1.ID-1
WHERE t1.ID > (SELECT MIN(ID) FROM table)
Basically, you need to join the table with itself, and use "t1.ID = t2.ID-1" to associate item no. 2 in one table with item no. 1 in the other table and then calculate the time difference between the two. In order to avoid accessing item no. 0 which doesn't exist, use the "T1.ID > (SELECT MIN(ID) FROM table)" clause to start from the second item.
Marc
At a guess:
SELECT AVG(timestamp)
I think you need to provide more information in your question for us to help.
If you mean difference between each-other row:
select AVG(x) from (
select a.timestamp - b.timestamp as x
from table a, table b -- this multiplies a*b ) sub
SELECT AVG(T2.Timestamp - T1.TimeStamp)
FROM Table T1
JOIN Table T2 ON T2.ID = T1.ID + 1
try this
Select Avg(E.Timestamp - B.Timestamp)
From Table B Join Table E
On E.Timestamp =
(Select Max(Timestamp)
From Table
Where Timestamp < R.Timestamp)