Measuring two arrays for equality of lowest numbers - sql

I have the following SQL Tables:
create table events (
sensor_id integer not null,
event_type integer not null,
value integer not null,
time timestamp unique not null
);
And it looks something like this:
sensor_id | event_type | value | time
-----------+------------+------------+--------------------
2 | 2 | 5 | 2014-02-13 12:42:00
2 | 4 | -42 | 2014-02-13 13:19:57
2 | 2 | 2 | 2014-02-13 14:48:30
3 | 2 | 7 | 2014-02-13 12:54:39
2 | 3 | 54 | 2014-02-13 13:32:36
what is the easiest way to return the most recent value in terms of time by sensor_id and event_type? so it looks like this:
sensor_id | event_type | value
-----------+------------+-----------
2 | 2 | 2
2 | 3 | 54
2 | 4 | -42
3 | 2 | 7
I cant get my head around it

try the t-sql code below:
SELECT e.sensor_id, e.event_type, e.value
FROM
(SELECT e.sensor_id, time = MAX(e.time)
FROM dbo.events e WITH(NOLOCK)
GROUP BY e.sensor_id, e.event_type) m
JOIN dbo.events e WITH(NOLOCK) ON e.sensor_id = m.sensor_id
AND e.time = m.time
ORDER BY e.sensor_id
how are your sorting the rows? can't seem to see the pattern.
EDIT: got the sorting now!
SELECT e.sensor_id, e.event_type, e.value
FROM
(SELECT e.sensor_id, time = MAX(e.time)
FROM dbo.events e WITH(NOLOCK)
GROUP BY e.sensor_id, e.event_type) m
JOIN dbo.events e WITH(NOLOCK) ON e.sensor_id = m.sensor_id
AND e.time = m.time
ORDER BY e.sensor_id, e.sensor_id + e.event_type

One way is to do:
SELECT value FROM events WHERE sensor_id=? AND event_type=? ORDER BY time DESC
Then the first one is the most recent.
Databases can sometimes limit you to just one, depending on the database you want.
I put a question mark where you would need to put a number.

SELECT
sensor_id, event_type, value
FROM
(
SELECT
ROW_NUMBER() OVER
(PARTITION BY sensor_id, event_type ORDER BY time DESC) AS Ordering,
*
FROM events
) data
WHERE
data.Ordering = 1

Related

Unique query give me duplicate rows

I have a database in SQL Server and one table which I have to use to display unique values base on column_one without using distinct so I came up with solution:
select p.id, p.one, two, w.five, p.eight
from table_one p with (nolock)
join table_two w with (nolock) on w.one = p.one
where
w.eight between convert(date, '10/05/2020', 103) and dateadd(d, 7, convert(date, '10/05/2020', 103)) and
p.twelve = 2
and p.id in (SELECT max(id) FROM table_one a with(nolock) GROUP BY two)
order by p.id desc
and I should get two rows, but I have 3, second row is duplicated? Why is that? I was trying to googling some examples and I found my solution as one of them. So what is wrong with it? Any suggestion will be helpful.
PS. I can confirm that subquery select max(id)... give me unique values.
EDITED
Sorry for missing that example earlier.
I hope is more clear now, what I want achieve.
table_one
id | one | two | eight| twelve
-------------------------------------
1 | value_1 | r1c2 | r1c8 | 2
2 | value_1 | r2c2 | r2c8 | 2
3 | value_2 | r3c2 | r3c8 | 2
4 | value_2 | r4c2 | r4c8 | 2
table_two
id | one | five | eight
---------------------------------
1 | value_1 | r1c5 | 22/03/2020
2 | value_1 | r2c5 | 24/03/2020
3 | value_2 | r3c5 | 24/03/2020
4 | value_2 | r4c5 | 25/04/2020
result expected:
id | one | two | eight
-----------------------------------
2 | value_1 | r2c2 | 24/03/2020
4 | value_2 | r4c2 | 25/04/2020
I think I figured it out, but please correct me if I am wrong, is that because I am JOINing table on column one which is not unique?
It's difficult without sample data and expected output, but I think that the following approach using ROW_NUMBER() is a possible option. You need to use the correct columns in the PARTITION BY and ORDER BY clauses:
SELECT *
FROM (
select
p.id, p.one, p.two, w.five, p.eight,
ROW_NUMBER() OVER (PARTITION BY p.two ORDER BY p.id DESC) AS rn
from table_one p with (nolock)
join table_two w with (nolock) on w.one= p.one
where
w.eight between convert(date, '10/05/2020', 103) and dateadd(d, 7, convert(date, '10/05/2020', 103)) and
p.two = 2
) t
WHERE t.rn = 1
ORDER by t.id DESC
That's true because when you join two tables on one column and it has duplicates values in that field, you get duplicate rows in your results. for your task, you can use window functions like this:
SELECT *
FROM (
select
p.*,ROW_NUMBER() OVER (PARTITION BY w.one ORDER BY w.eight DESC) AS rn
from table_one p
join table_two w on w.one= p.one
) t
WHERE t.rn = 1
ORDER by t.id asc

SQL query to find the visitor together with the date time

My visitor log table has id, visitor, department,vtime fields.
id | visitor | Visittime | Department_id
--------------------------------------------------------------
1 1 2019-05-07 13:53:50 1
2 2 2019-05-07 13:56:54 1
3 1 2019-05-07 14:54:10 3
4 2 2019-05-08 13:54:49 1
5 1 2019-05-08 13:58:15 1
6 2 2019-05-08 18:54:30 2
7 1 2019-05-08 18:54:37 2
And I have already have the following index
CREATE INDEX Idx_VisitorLog_Visitor_VisitTime_Includes ON VisitorLog
(Visitor, VisitTime) INCLUDE (DepartmentId, ID)
From the above table 4 filters are passed from User interface, visitor 1 and visitor 2 and visiting start time and end time.
In what are the department visitor 1 and visitor 2 both together with the VisitTime difference with in 5 mins those need to be filtered
Output shout be
id | visitor | Visittime | Department_id
--------------------------------------------------------------
1 1 2019-05-07 13:53:50 1
2 2 2019-05-07 13:56:54 1
4 2 2019-05-08 13:54:49 1
5 1 2019-05-08 13:58:15 1
For that I had used the following query,
;with CTE1 AS(
Select id,visitor,Visittime,department_id from visitorlog where visitor=1
)
,CTE2 AS(
Select id,visitor,Visittime,department_id from visitorlog where visitor=2
)
select * from CTE2 V2
Inner join CTE1 V1 on V2.department_id=V1.department_id and DATEDIFF(minute,V2.Visittime,V1.Visittime)between -5 and 5**
The above query takes too much of time to give response. Because in my table, almost 20 million records are available
Could any one suggest the correct way for my requirement.
Thanks in advance
This is a completely revised answer, based upon your additional information above.
After reviewing the data file above and the results you desire, this seems like the cleanest way to provide your results. First, we need a different index:
create index idx_POC_visitorlog on visitorlog
(visitor, Department_id, Visittime) include(id);
With this index, we can limit the queries to only the two passed in IDs. To simulate that, I created variables to hold their values. This query returns the data you are looking for.
DECLARE #Visitor1 int = 1,
#Visitor2 int = 2
;with t as (
select Department_id,
dateadd(minute, -5, visittime) as EarlyTime,
dateadd(minute, 5, Visittime) as LateTime,
id
from visitorlog
where visitor = #Visitor1
),
v as (
select v.id,
t.id as tid
from visitorlog v
INNER JOIN t
ON v.visitor = #Visitor2
AND v.Department_id = t.Department_id
and v.Visittime BETWEEN t.EarlyTime and t.LateTime
)
SELECT *
FROM visitorlog vl
WHERE ID IN (
SELECT v.id
FROM v
UNION
SELECT v.tid
FROM v
)
ORDER BY visittime;
If your version of SQL Server supports the LAG and LEAD functions, try rewriting the query as follows:
with t as (
select
*,
dateadd(minute, 5,
lag(Visittime) over(partition by Department_id order by Visittime)) lag_visit_time,
dateadd(minute, -5,
lead(Visittime) over(partition by Department_id order by Visittime)) lead_visit_time
from visitorlog
where visitor in(1, 2)
)
select
id, visitor, visittime, department_id
from t
where lag_visit_time >= Visittime or lead_visit_time <= Visittime;
This index is called a POC.
Results:
+----+---------+----------------------+---------------+
| id | visitor | visittime | department_id |
+----+---------+----------------------+---------------+
| 1 | 1 | 2019-05-07T13:53:50Z | 1 |
| 2 | 2 | 2019-05-07T13:56:54Z | 1 |
| 4 | 2 | 2019-05-08T13:54:49Z | 1 |
| 5 | 1 | 2019-05-08T13:58:15Z | 1 |
| 6 | 2 | 2019-05-08T18:54:30Z | 2 |
| 7 | 1 | 2019-05-08T18:54:37Z | 2 |
+----+---------+----------------------+---------------+
Demo.

postgresql - How to get one row the min value

I have table (t_image) with this column
datacd | imagecode | indexdate
----------------------------------
A | 1 | 20170213
A | 2 | 20170213
A | 3 | 20170214
B | 4 | 20170201
B | 5 | 20170202
desired result is this
datacd | imagecode | indexdate
----------------------------------
A | 1 | 20170213
B | 4 | 20170201
In the above table, I want to retrieve 1 row for each datacd who has the minimum index date
Here is my query, but the result returns 2 rows for datacd A
select *
from (
select datacd, min(indexdate) as indexdate
from t_image
group by datacd
) as t1 inner join t_image as t2 on t2.datacd = t1.datacd and t2.indexdate = t1.indexdate;
The Postgres proprietary distinct on () operator is typically the fastest solution for greatest-n-per-group queries:
select distinct on (datacd) *
from t_image
order by datacd, indexdate;
One option uses ROW_NUMBER():
SELECT t.datacd,
t.imagecode,
t.indexdate
FROM
(
SELECT datacd, imagecode, indexdate,
ROW_NUMBER() OVER (PARTITION BY datacd ORDER BY indexdate) rn
FROM t_image
) t
WHERE t.rn = 1

SQL Server - Select Distinct of two columns, where the distinct column selected has a maximum value based on two other columns

I have 2 tables - TC and T, with columns specified below. TC maps to T on column T_ID.
TC
----
T_ID,
TC_ID
T
-----
T_ID,
V_ID,
Datetime,
Count
My current result set is:
V_ID TC_ID Datetime Count
----|-----|------------|--------|
2 | 1 | 2013-09-26 | 450600 |
2 | 1 | 2013-12-09 | 14700 |
2 | 1 | 2014-01-22 | 15000 |
2 | 1 | 2014-01-22 | 15000 |
2 | 1 | 2014-01-22 | 7500 |
4 | 1 | 2014-01-22 | 1000 |
4 | 1 | 2013-12-05 | 0 |
4 | 2 | 2013-12-05 | 0 |
Using the following query:
select T.V_ID,
TC.TC_ID,
T.Datetime,
T.Count
from T
inner join TC
on TC.T_ID = T.T_ID
Result set I want:
V_ID TC_ID Datetime Count
----|-----|------------|--------|
2 | 1 | 2014-01-22 | 15000 |
4 | 1 | 2014-01-22 | 1000 |
4 | 2 | 2013-12-05 | 0 |
I want to write a query to select each distinct V_ID + TC_ID combination, but only with the maximum datetime, and for that datetime the maximum count. E.g. for the distinct combination of V_ID = 2 and TC_ID = 1, '2014-01-22' is the maximum datetime, and for that datetime, 15000 is the maximum count, so select this record for the new table. Any ideas? I don't know if this is too ambitious for a query and I should just handle the result set in code instead.
One method uses row_number():
select v_id, tc_id, datetime, count
from (select T.V_ID, TC.TC_ID, T.Datetime, T.Count,
row_number() over (partition by t.V_ID, tc.tc_id
order by datetime desc, count desc
) as seqnum
from t join
tc
on tc.t_id = t._id
) tt
where seqnum = 1;
The only issue is that some rows have the same maximum datetime value. SQL tables represent unordered sets, so there is no way to determine which is really the maximum -- unless the datetime really has a time component or another column specifies the ordering within a day.
It is possible to solve this using CTEs. First, extracting the data from your query. Second, get the maxdates. Third, get the highest count for each maxdate.:
;WITH Dataset AS
(
select T.V_ID,
TC.TC_ID,
T.[Datetime],
T.[Count]
from T
inner join TC
on TC.T_ID = T._ID
),
MaxDates AS
(
SELECT V_ID, TC_ID, MAX(t.[Datetime]) AS MaxDate
FROM Dataset t
GROUP BY t.V_ID, t.TC_ID
)
SELECT t.V_ID, t.TC_ID, t.[Datetime], MAX(t.[Count]) AS [Count]
FROM Dataset t
INNER JOIN MaxDates m ON t.V_ID = m.V_ID AND t.TC_ID = m.TC_ID AND m.MaxDate = t.[Datetime]
GROUP BY t.V_ID, t.TC_ID, t.[Datetime]
Just to keep it simple:
You need to group by T.V_ID,TC.TC_ID,
with selecting the max of date and then to get the maximum count, you must use a sub query as follows,
select T.V_ID,
TC.TC_ID,
max(T.Datetime) as Date_Time,
(select max(Count) from T as tb where v_ID = T.v_ID and DateTime = max(T.DateTime)) as Count
from T
inner join TC
on TC.T_ID = T._ID
group by T.V_ID,TC.TC_ID,

subtract data from single column

I have a database table with 2 columns naming piece and diff and type.
Here's what the table looks like
id | piece | diff | type
1 | 20 | NULL | cake
2 | 15 | NULL | cake
3 | 10 | NULL | cake
I want like 20 - 15 = 5 then 15 -10 = 5 , then so on so fort with type as where.
Result will be like this
id | piece | diff | type
1 | 20 | 0 | cake
2 | 15 | 5 | cake
3 | 10 | 5 | cake
Here's the code I have so far but i dont think I'm on the right track
SELECT
tableblabla.id,
(tableblabla.cast(pieces as decimal(7, 2)) - t.cast(pieces as decimal(7, 2))) as diff
FROM
tableblabla
INNER JOIN
tableblablaas t ON tableblabla.id = t.id + 1
Thanks for the help
Use LAG/LEAD window function.
Considering that you want to find Difference per type else remove Partition by from window functions
select id, piece,
Isnull(lag(piece)over(partition by type order by id) - piece,0) as Diff,
type
From yourtable
If you are using Sql Server prior to 2012 use this.
;WITH cte
AS (SELECT Row_number()OVER(partition by type ORDER BY id) RN,*
FROM Yourtable)
SELECT a.id,
a.piece,
Isnull(b.piece - a.piece, 0) AS diff,
a.type
FROM cte a
LEFT JOIN cte b
ON a.rn = b.rn + 1