I have two tables like these:
Table1
Timestamp
value
2022-07-04 16:16:50
120
2022-07-04 16:17:25
110
2022-07-04 16:17:35
105
2022-07-04 16:17:45
130
Table2
Begin_Timestamp
End_Timestamp
2022-07-04 16:14:00
2022-07-04 16:17:02
2022-07-04 16:17:11
2022-07-04 16:17:30
2022-07-04 16:17:38
2022-07-04 16:17:47
I want to join the two tables based on their timestamp. So if the table1.timestamp is between table2.Begin_timestamp and table2.End_timestamp, it would add "isFound=1". For example, the first row of Table1 is 16:16:50 and is between 16:14:00 and 16:17:02 (the first row of Table2). I want a table like this:
Wanted table
Timestamp
value
isFound
2022-07-04 16:16:50
120
1
2022-07-04 16:17:25
110
1
2022-07-04 16:17:35
105
0
2022-07-04 16:17:45
130
1
I tried the following but it only works for the last row.
SELECT t1.timestamp,
t1.value,
(CASE WHEN (t1.Timestamp BETWEEN t2.Begin_Timestamp AND t2.End_Timestamp)
THEN '1'
ELSE '0') AS isFound
FROM Table1 t1
LEFT JOIN (
SELECT *
FROM Table2
) AS t2
ON t1.Timestamp BETWEEN t2.Begin_Timestamp AND t2.End_Timestamp
)
RESULT :
Timestamp
value
isFound
2022-07-04 16:16:50
120
NULL
2022-07-04 16:17:25
110
NULL
2022-07-04 16:17:35
105
NULL
2022-07-04 16:17:45
130
1
I use MS-SQL server. Can someone help me with that? I feel like this it is easy but I don't find the problem. Thanks!
You can do a LEFT JOIN between the two tables on the conditions that the "Table1.Timestamp" is found between the two "Table2" timestamps.
Then you can exploit the non-matching rows having both "Begin_Timestamp" and "End_Timestamp" equal to NULL inside your CASE statement for the creation of the "isFound" field.
SELECT table1.*,
CASE WHEN [Begin_Timestamp] IS NULL THEN 0 ELSE 1 END AS isFound
FROM table1
LEFT JOIN table2
ON table2.[Begin_Timestamp] < table1.[Timestamp]
AND table2.[End_Timestamp] > table1.[Timestamp]
Check the demo here.
Note: this solution assumes that all your "table2" timestamp periods are disjoint among each other, otherwise you need to add the DISTINCT keyword right after the SELECT keyword.
You can use case expression combined with an exists check:
select *,
case when exists (
select * from t2
where t1.Timestamp between t2.Begin_Timestamp and t2.End_Timestamp
) then 1 else 0 end IsFound
from t1;
Related
I have a temp table that looks something like this:
Record DepartmentId PositionId EmployeeId StatusId CustomerId
1 Null Null Null 4
2 7 454 Null Null
3 Null 454 Null 3
3 Null Null Null Null 214
3 Null Null Null Null 100
3 Null Null Null Null 312
4 Null Null Null Null 357
I inserted the above into the temp table from tables that looked like this:
Record Table Record-to-Department Record-to-Position
Record Name Record DepartmentId Record PositionId
1 Red 2 7 2 454
2 blue 3 454
3 Green
4 Purple
Record-To-Status Record-To-Customer
Record StatusId Record CustomerId
1 4 3 214
3 3 3 100
3 312
4 357
I have an employee whose record looks something like this:
EmployeeId DepartmentId PositionId StatusId
342 7 454 4
Employee Customers:
EmployeeId CustomerId
342 357
342 95
342 720
In this scenario, it would return Record 1 (because it matches the StatusId), Record 2 (because it matches both the DepartmentId and the PositionId), but it would not return Record 3 because it only matches the PositionId and not the StatusId, and it would return RecordId 4 because one of the Employee CustomerIds matches the CustomerId on Record 4.
I got part of this answer on another question enter link description here (please forgive me I am new and trying to figure out how to ask everything I need to know), but I can't figure out how to handle the multi-records.
I tried selecting the Employees customer Id's into a table variable and then attempted to use the Coalesce like this:
Declare #Customers table(CustomerId int)
INSERT INTO #Customers(CustomerId)
SELECT DISTINCT S.CustomerId
FROM employee_Customers
Select * from tbl
WHERE
COAlesce(StatusId,#StatusId)=#StatusId AND
COALESCE(DepartmentId,#DepartmentId)=#DepartmentId AND
Coalesce(PositionId,#PositionId)=#PositionId AND
Coalesce(EmployeeCompanyId,#EmployeeCompanyId) = #EmployeeCompanyId AND
COALESCE((Select CustomerId from tbl_Requirement_to_Customer),(Select CustomerId from #Customers)) = (Select CustomerId from #Customers)
But I receive the error "Subquery Returned more than 1 value".
I have a possible solution you can try. I don't think it will be plug-and-play but hopefully you can adapt it to your situation. I am using just the data as presented in your temp table, your employee record and your Employee-customers correlation.
The basic logic is to join your temp table to the employee(s) using or condition, but then to get a count of populated values, and compare this count to a count of the number of matching values, which must be at least the first count and greater than zero.
This returns your desired output:
select t.*
from Temp t
left join emp e on e.DepartmentId=t.DepartmentId or e.PositionId=t.PositionId or e.EmployeeId=t.EmployeeId or e.StatusId=t.StatusId
outer apply (
select case when exists (
select * from EmployeeCustomers ec join emp e on e.EmployeeId=ec.EmployeeId where ec.CustomerID=t.CustomerId
) then 1 else 0 end CustomerIdMatch
)c
outer apply (
values (
Iif(t.departmentId is null,0,1) +
Iif(t.PositionId is null,0,1) +
Iif(t.EmployeeId is null,0,1) +
Iif(t.StatusId is null,0,1) +
c.CustomerIdMatch
))x(Cnt)
outer apply (
values (
Iif(t.departmentId=e.DepartmentId,1,0) +
Iif(t.PositionId=e.PositionId,1,0) +
Iif(t.EmployeeId=e.EmployeeId,1,0) +
Iif(t.StatusId=e.StatusId,1,0) +
c.CustomerIdMatch
))y(Cnt2)
where cnt2>=cnt and cnt2>0
See working DB<>Fiddle
I have a cumbersome query I'm building in a certain way as I'll be calling it from the C-API substituting certain values. I'm having an issue where I'm expecting NULL fields to be populating the final table.
To populate my query, I generate a date column using a recursive table expression and joining another table twice.
An example set from my table's data:
SELECT * FROM myTable;
id foreignId date value
---------- ---------- ---------- ----------
1 1 2019-12-01 100
2 1 2019-12-02 101
3 1 2019-12-03 102
4 1 2019-12-04 103
5 1 2019-12-07 104
6 2 2019-12-01 200
7 2 2019-12-02 201
8 2 2019-12-03 202
9 2 2019-12-07 203
The query I'm using:
WITH RECURSIVE dates(date) AS (
VALUES('2019-12-01')
UNION ALL
SELECT date(date, '+1 day')
FROM dates
WHERE date < '2019-12-07'
)
SELECT a.date, b.myTable, c.myTable
FROM dates a
LEFT JOIN myTable b ON a.date = b.date
LEFT JOIN myTable c ON a.date = c.date
WHERE b.foreignId = 1 AND c.foreignId = 2;
Returns the table:
date myTable myTable
---------- ---------- ----------
2019-12-01 100 200
2019-12-02 101 201
2019-12-03 102 202
2019-12-07 104 203
What I am trying to achieve:
date myTable myTable
---------- ---------- ----------
2019-12-01 100 200
2019-12-02 101 201
2019-12-03 102 202
2019-12-04 103
2019-12-05
2019-12-06
2019-12-07 104 203
I've tried using IFNULL in the SELECT statement like:
...
SELECT a.date, IFNULL(b.myTable, 0) b.myTable, IFNULL(c.myTable, 0) c.myTable
...
Which returns:
Error: near ".": syntax error
I'm not certain what the syntax error is, and haven't got that part working to test the result.
I've also tried using CROSS JOIN in place of LEFT JOIN and various combinations, but they return the same table as the LEFT JOIN. Can anyone give me some guidance, particularly anything in the documentation I may have missed?
Move the condition on the left joined tables from the where clause to the on part of the join. Otherwise, rows where the left join comes up empty are filtered out by the where clause (since the conditions are not be fulfilled): this actually turns your left join to an inner join.
WITH RECURSIVE dates(date) AS ( ...)
SELECT a.date, b.myTable, c.myTable
FROM dates a
LEFT JOIN myTable b ON a.date = b.date AND b.foreignId = 1
LEFT JOIN myTable c ON a.date = c.date AND c.foreignId = 2;
I am trying to Create a SQL View by joining two SQL tables and return only the lowest value from second table and all the rows from first table similar to left join.
My problem can be clearly explained with the below example.
Table1
Id Product Grade Term Bid Offer
100 ABC A Q1 10 20
101 ABC A Q1 5 25
102 XYZ A Q2 25 30
103 XYZ B Q2 20 30
Table2
Id Product Grade Term TradeValue
1 ABC A Q1 100
2 ABC A Q1 95
3 XYZ B Q2 100
In the above data I want to join Table1 and Table2 when ever the columns Product,Grade and Term from both the tables are equal and return all the rows from Table1 while joining the lowest Value of the column TradeValue from Table2 to the first record of the match and making TradeValue as NULL for other rows of the resultant View and the resultant View should have the Id of Table2 as LTID
So the resultant SQL View should be
RESULT
Id Product Grade Term Bid Offer TradeValue LTID
100 ABC A Q1 10 20 95 2
101 ABC A Q1 5 25 NULL 2
102 XYZ A Q2 25 30 NULL NULL
103 XYZ B Q2 20 30 100 3
I tried using the following query
CREATE VIEW [dbo].[ViewCC]
AS
SELECT
a.Id,a.Product,a.Grade,a.Term,a.Bid,a.Offer,
b.TradeValue
FROM Table1 AS a
left JOIN (SELECT Product,Grade,Term,MIN(TradeValue) TradeValue from Table2 Group by Product,Grade,Term,) AS b
ON b.Product=a.Product
and b.Grade=a.Grade
and b.Term=a.Term
GO
The above Query returned the following data which is apt to the query I wrote but that is not what I was trying to get
Id Product Grade Term Bid Offer TradeValue
100 ABC A Q1 10 20 95
101 ABC A Q1 5 25 95 --This should be null
102 XYZ A Q2 25 30 NULL
103 XYZ B Q2 20 30 100
As we can see minimum value of TradeValue being assigned to all matching rows in Table1 and also I was not able to return Id As LTID from Table2 as I have issues with group by clause as I cannot group it by b.Id as it returns too many rows.
May I know a better way to deal with this?
You need a row number attached to each record from Table1, so that the requirement of only joining the first record from each group of Table1 can be fulfilled:
CREATE VIEW [dbo].[ViewCC]
AS
SELECT a.Id, a.Product, a.Grade, a.Term, a.Bid, a.Offer,
b.TradeValue, b.Id AS LTID
FROM (
SELECT *, ROW_NUMBER() OVER(PARTITION BY Product, Grade, Term ORDER BY Id) AS rn
FROM Table1
) a
OUTER APPLY (
SELECT TOP 1 CASE WHEN rn = 1 THEN TradeValue
ELSE NULL
END AS TradeValue, Id
FROM Table2
WHERE Product=a.Product AND Grade=a.Grade AND Term=a.Term
ORDER BY TradeValue) b
GO
OUTER APPLY returns a table expression containing either the matching record from Table2 with the lowest TradeValue, or NULL if no matching record exists.
I want to number some base rows in table without mixing the ordering. I have table like this:
Status ProductId
A 12
NULL 25
B 35
C 56
NULL 89
NULL 99
D 120
E 140
I want to add No column, to count Statuses which is not null with same ProductId ordering, but, don't want to count NULL rows. I want the result like this:
No Status ProductId
1 A 12
NULL 25
2 B 35
3 C 56
NULL 89
NULL 99
4 D 120
5 E 140
I work on SQL Sever 2008, SSRS. Someone can give solution in SQL side or in RDL file.
You can do this:
WITH CTE
AS
(
SELECT
ROW_NUMBER() OVER(ORDER BY Status) AS No,
Status, ProductId
FROM table1
WHERE Status IS NOT NULL
)
SELECT
c.No,
t.Status,
t.ProductId
FROM table1 AS t
LEFT JOIN CTE AS c ON c.ProductId = t.ProductId
ORDER BY ProductId;
SQL Fiddle Demo
You can use this query directly in your report.
I have one problem in sql server.I have some records like
PKId EquipmentID StudentId Issueddate Returneddate
1 116 230 2014-01-14 17:14:58.940 2014-01-18 14:12:038.876
2 116 237 2014-01-14 17:14:58.940 NULL
3 117 400 2014-01-14 17:14:58.940 2014-01-18 14:12:038.876
Here EquipmentID and StudentId are the foreign key.We need to write a query which gives us data based on Returneddate.We need to check condition one like in first row equipmentid is 116 and it's assigned to studentId 230 where Returneddate is not null means for now this 116 equipment is free means it is unassiged but in the next line same equipment is assigned to student 237 and hiis returneddate is NULL means this equipment is assined to someone and in last case equipmentid 117 assigned to studentid 400 and it's returneddate is not null means it is available.
So we need to show only those records which is available.If i took this case as example then it will give me
3 117 400 2014-01-14 17:14:58.940 2014-01-18 14:12:038.876 row as a output.
I Tried:
select * from Equipment where (EquipmentID not in (select EquipmentID
from PEquip where Returneddate is null))
Please help me.
Hope you understand.
If I've got it right you need EquipmentID for which there are no rows with NULL Returneddate.
SELECT * FROM T as T1
WHERE NOT EXISTS (SELECT * FROM T
WHERE EquipmentID=T1.EquipmentID
AND Returneddate IS NULL)
select * from EuipmentDetails where EquipmentID
not in (select EquipmentID from EuipmentDetails where Returneddate is NULL )
Try this:
select * from theTable t1 where returneddate =
(select max Issueddate from theTable t2 where t1.EquipmentId = t2.EquipmentId)
and returneddate is not NULL;
Assuming that the order of PkId is consistent with the chronology of the data, I'd go with
SELECT PKId, EquipmentID, StudentId, Issueddate, Returneddate
FROM Equipment E
INNER JOIN (SELECT MAX(PKId) AS PKId FROM Equipment GROUP BY EquipmentId) AS T
ON E.PKId = T.PKId
WHERE E.ReturnedDate IS NOT NULL
Logic: select the latest entry for each EquipmentId, IF the latest entry has ReturnedDate not null.