Get a Row if within certain time period of other row - sql

I have a SQL statement that I am currently using to return a number of rows from a database:
SELECT
as1.AssetTagID, as1.TagID, as1.CategoryID,
as1.Description, as1.HomeLocationID, as1.ParentAssetTagID
FROM Assets AS as1
INNER JOIN AssetsReads AS ar ON as1.AssetTagID = ar.AssetTagID
WHERE
(ar.ReadPointLocationID='Readpoint1' OR ar.ReadPointLocationID='Readpoint2')
AND (ar.DateScanned between 'LastScan' AND 'Now')
AND as1.TagID!='000000000000000000000000'
I am wanting to do a query that will get the row with the oldest DateScanned from this query and also get another row from the database if there was one that was within a certain period of time from this row (say 5 seconds for an example). The oldest record would be relatively simple by selecting the first record in a descending sort, but how would I also get the second record if it was within a certain time period of the first?
I know I could do this process with multiple queries, but is there any way to combine this process into one query?
The database that I am using is SQL Server 2008 R2.
Also please note that the DateScanned times are just placeholders and I am taking care of that in the application that will be using this query.

Here is a fairly general way to approach it. Get the oldest scan date using min() as a window function, then use date arithmetic to get any rows you want:
select t.* -- or whatever fields you want
from (SELECT as1.AssetTagID, as1.TagID, as1.CategoryID,
as1.Description, as1.HomeLocationID, as1.ParentAssetTagID,
min(DateScanned) over () as minDateScanned, DateScanned
FROM Assets AS as1
INNER JOIN AssetsReads AS ar ON as1.AssetTagID = ar.AssetTagID
WHERE (ar.ReadPointLocationID='Readpoint1' OR ar.ReadPointLocationID='Readpoint2')
AND (ar.DateScanned between 'LastScan' AND 'Now')
AND as1.TagID!='000000000000000000000000'
) t
where datediff(second, minDateScanned, DateScanned) <= 5;

I am not really sure of sql server syntax, but you can do something like this
SELECT * FROM (
SELECT
TOP 2
as1.AssetTagID,
as1.TagID,
as1.CategoryID,
as1.Description,
as1.HomeLocationID,
as1.ParentAssetTagID ,
ar.DateScanned,
LAG(ar.DateScanned) OVER (order by ar.DateScanned desc) AS lagging
FROM
Assets AS as1
INNER JOIN AssetsReads AS ar
ON as1.AssetTagID = ar.AssetTagID
WHERE (ar.ReadPointLocationID='Readpoint1' OR ar.ReadPointLocationID='Readpoint2')
AND (ar.DateScanned between 'LastScan' AND 'Now')
AND as1.TagID!='000000000000000000000000'
ORDER BY
ar.DateScanned DESC
)
WHERE
lagging IS NULL or DateScanned - lagging < '5 SECONDS'
I have tried to sort the results by DateScanned desc and then just the top most 2 rows. I have then used the lag() function on DateScanned field, to get the DateScanned value for the previous row. For the topmost row the DateScanned shall be null as its the first record, but for the second one it shall be value of the first row. You can then compare both of these values to determine whether you wish to display the second row or not
more info on the lagging function: http://blog.sqlauthority.com/2011/11/15/sql-server-introduction-to-lead-and-lag-analytic-functions-introduced-in-sql-server-2012/

Related

Add previous load count using the the present count and the timestamp column

I have a table with the following columns
id, timestamp, current load count, previous load count
and it has many rows. I have values for all the first three columns, but for the "previous load count", I need to get the count of the date one day before the count of the current load count.
See the below image (table example) to view the sample table
For example: previous load count of id:4 is the count same as the current load count of id:5.
Is there anyway to write a SQL statement to update the previous load count?
Can you try this?
SELECT [id]
,[timestamp]
,[current load count]
,LAG([current load count]) OVER (ORDER BY [timestamp] ASC, [id]) AS [previous load count]
FROM [table]
The LAG function can be used to access data from a previous row in the same result set without the use of a self-join.
It is available after SQL Server 2012.
In the example I added ordering by id, too - in case you have records with same date, but you can remove it if you like.
If you need exactly one day before, consider a join:
select t.*, tprev.load_count as prev_load_count
from t left join
t tprev
on tprev.timestamp = dateadd(day, -1, t.timestamp);
(Note: If the timestamp has a time component, you will need to convert to a date.)
lag() gives you the data from the previous row. If you know you have no gaps, then these are equivalent. However, if there are gaps, then this returns NULL on the days after the gap. That appears to be what you are asking for.
You can incorporate either this or lag() into an update:
update t
set prev_load_count = tprev.load_count
from t join
t tprev
on tprev.timestamp = dateadd(day, -1, t.timestamp);

SQL script to find previous value, not necessarily previous row

is there a way in SQL to find a previous value, not necessarily in the previous row, within the same SELECT statement?
See picture below. I'd like to add another column, ELAPSED, that calculates the time difference between TIMERSTART, but only when DEVICEID is the same, and I_TYPE is viewDisplayed. e.g. subtract 1 from 2, store difference in 3, store 0 in 4 because i_type is not viewDisplayed, subtract 2 from 5, store difference in 6, and so on.
It has to be a statement, I can't use a stored procedure in this case.
SELECT DEVICEID, I_TYPE, TIMERSTART,
O AS ELAPSED -- CASE WHEN <CONDITION> THEN TIMEDIFF() ELSE 0 END AS ELAPSED
FROM CLIENT_USAGE
ORDER BY TIMERSTART ASC
I'm using SAP HANA DB, but it works pretty much like the latest version of MS-SQL. So, if you know how to make it work in SQL, I can make it work in HANA.
You can make a subquery to find the last time entered previous to the row in question.
select deviceid, i_type, timerstart, (timerstart - timerlast) as elapsed.
from CLIENT_USAGE CU
join ( select top 1 timerstart as timerlast
from CLIENT_USAGE C
where (C.i_type = CU.i_type) and
(C.deviceid = CU.deviceid) and (C.timerstart < CU.timerstart)
order by C.timerstart desc
) as temp1
on temp1.i_type = CU.i_type
order by timerstart asc
This is a rough sketch of what the sql should look like I do not know what your primary key is on this table if it is i_type or i_type and deviceid. But this should help with how to atleast calculate the field. I do not think it would be necessary to store the value unless this table is very large or the hardware being used is very slow. It can be calculated rather easily each time this query is run.
SAP HANA supports window functions:
select DEVICEID,
TIMERSTART,
lag(TIMERSTART) over (partition by DEVICEID order by TIMERSTART) as previous_start
from CLIENT_USAGE
Then you can wrap this in parentheses and manipulate the data to your hearts' content

Access: Compare current field value in subquery

I am trying to create a subquery in MS Access where the having clause compares a value on the current record. I created the queries separate, but am having a hard time trying to combine them.
I have the following query, which is a Purchase Order list (POsFullDetail), and should show the first occurrence of the date of a PO given the Stock number (Stockum):
SELECT POsFullDetail.PO, POsFullDetail.OrderDate, POsFullDetail.StockNum,
(SELECT First(POsFullDetail.OrderDate) AS FirstOfOrderDate
FROM POsFullDetail
GROUP BY POsFullDetail.StockNum
HAVING POsFullDetail.StockNum = POsFullDetail.StockNum.Value
ORDER BY First(POsFullDetail.OrderDate)
) AS First_Date
FROM POsFullDetail;
The statement that I am trying to work with is POsFullDetail.StockNum.Value
The way it is set up, it's asking for a value. When I created the subquery separate I entered the stock number directly.
The subquery gives you the first order date per stocknum.
When using it as a subquery, you are no longer interested in the first order date per stocknum, but in the first order date for the stocknum.
SELECT POsFullDetail.PO, POsFullDetail.OrderDate, POsFullDetail.StockNum,
(
SELECT First(SameStockNum.OrderDate) AS FirstOfOrderDate
FROM POsFullDetail AS SameStockNum
WHERE SameStockNum.StockNum = POsFullDetail.StockNum
) AS First_Date
FROM POsFullDetail;
As you see, you must use a table alias, so you can link the table to itself. Though working with the same table you call it one time POsFullDetail and one time SameStockNum which enables you to link by SameStockNum.StockNum = POsFullDetail.StockNum.

SQL- get dates that were used in the WHERE clause?

We have a ERP that integrates nicely with Crystal Reports.
Now, we can add filters through this application, and it passes these to the report (not as parameters but somehow adds this to the WHERE clause).
The problem is, when filtering dates, we have no way in the report to determine what date range the user selected (as we want to show this date on the report).
Any idea how I can show this through SQL?
I was thinking of using the dual table, and selecting a huge list of dates, then using the MIN and MAX of these dates to determine which was selected. The problem is, I can't join this onto my original query without adding LOTS of rows.
I have this so far:
SELECT
MIN(DTE) MIN_DTE,
MAX(DTE) MAX_DTE
FROM
(
SELECT
TRUNC(SYSDATE)-(5*365) + ROWNUM AS DTE
FROM
DUAL
CONNECT BY
ROWNUM <= (10*365)
)
WHERE
DTE >= '12-NOV-07'
AND DTE <= '12-DEC-07'
But the problem is I can't work out how to join that to my original query without upsetting the row cont.
Any other ideas?
That query returns only one row, so it won't upset the row count at all, unless there is something else going on (like, maybe, the automatic filtering doesn't work in subqueries).
Otherwise, this should work as expected:
SELECT q.*, max_min.*
FROM ( ... put your original query here ...) q,
( ... put the subquery that returns one row with max & min here ...) max_min
That's all to it.

SQL Server 2008: Filtering Out Duplicate Rows Based on Multiple Columns

Thanks to everyone who helped me with my last question. This is a similar question, but now I have a better idea of what I want. Again I'm using MS SQL Server 2008, and I'm trying to figure out a query that is a little beyond my week of SQL experience.
Right now I have the following simple query
SELECT pl.val, pl.txt_val, pl.id
FROM dm.labs pl
WHERE pl.lab_nm = 'CK (CPK)'
AND pl.val < 999999;
AND pl.val IS NOT NULL
ORDER BY pl.val;
In this table, each row corresponds to the results of a patient's lab value. The problem is that for some patients, there are rows that are actually multiple copies of the same lab reading. There is a column pl.lab_filed_dts (datetime data type) giving the date the lab was taken.
What I want to do is:
Edit: if two (or more) rows have the same id, the same val, and the same lab_filed_dts, regardless of their values in any other column, I want to return val, txt_val, and id from only one of the rows (it doesn't matter which one).
Edit: if two rows have the same id, the same val, and the same day portion (but not necessarily time) of lab_filed_dts AND the time portion of lab_filed_dts for one of them is midnight, I want to return val, txt_val, and id from the row whose lab_filed_dts time is not midnight.
Thanks again for everyone's help!
If I understand your question correctly:
SELECT pl.val, pl.txt_val, pl.id
FROM dm.labs pl
WHERE pl.lab_nm = 'CK (CPK)'
AND pl.val < 999999;
AND pl.val IS NOT NULL
GROUP BY pl.val, pl.txt_val, pl.id, cast(lab_filed_dts as date)
HAVING lab_filed_dts = max(lab_filed_dts)
ORDER BY pl.val;
/* changed pl.vak to pl.val as you can't order on a column not in the select and I assumed it was just a type*/