SQL Query to display timekeeping table - sql

I have a table like this
id Marca CodCartela Line Post status Time
---- ------ ----------- ---- ---- ------ -----------------------
178 346 4516645709 AS01 55 1 2015-04-05 02:30:12.627
179 346 4516645709 AS01 55 0 2015-04-05 02:31:23.593
180 346 4516645709 AS01 88 1 2015-04-05 02:32:05.107
181 346 4516645709 AS01 88 0 2015-04-05 02:32:22.060
Status 1 means IN and status 0 means OUT.
What I want is to display in and out time on the same line for each person.
Example
id Marca CodCartela Line Post status TimeIN TimeOUT
---- ---------------- ---- ---- ------ -----------------------------------------
178 346 4516645709 AS01 55 1 2015-04-05 02:30:12.627 2015-04-05 02:31:23.593
Is this possible or I need to rethink all the timekeeping aplications :(

This will track each person's Ins and Outs. Just switch yourTable in the CTE to your actual table name.
WITH CTE_yourTable
AS
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY Marca ORDER BY [Time]) activity_num
FROM yourTable
)
SELECT A.ID,
A.Marca,
A.CodCartela,
A.[Line],
A.[Post],
--A.[Status],
A.[Time] AS TimeIn,
B.[Time] AS [TimeOut]
FROM CTE_yourTable A
LEFT JOIN CTE_yourTable B
ON A.Marca = B.Marca
AND A.activity_num = B.activity_num - 1
WHERE A.[Status] = 1
Results:
ID Marca CodCartela Line Post TimeIn TimeOut
----------- ----------- --------------------------------------- ---- ----------- ---------------------- ----------------------
178 346 4516645709 AS01 55 2015-04-0502:30:12.627 2015-04-0502:31:23.593
180 346 4516645709 AS01 88 2015-04-0502:32:05.107 2015-04-0502:32:22.060

Its simple use conditional Aggregate.
SELECT marca,
codcartela,
line,
post,
Max(CASE WHEN status = 1 THEN time END) AS TimeIN,
Max(CASE WHEN status = 0 THEN time END) AS TimeOUT
FROM yourtable
GROUP BY marca,
codcartela,
line,
post

Assuming that the combination post, status is unique you can do a join:
select
t1.*
,t2.Time as timeOut
from tab t1
left join tab t2
on t1.post = t2.post
and t2.status = 0
where t1.status = 1
Otherwise you might have to add additional conditions.

I don't know exactly how is the schema structure, and didn't get you well, I'm not sure but according to your sample data and desired output I think you want something like this:
select t1.marca,
t1.codcartela,
t1.line,
t1.post,
t1.time as TimeIN,
t2.time as TimeOUT
FROM table_name t1
LEFT OUTER JOIN table_name t2 on t1.post=t2.post
and t1.marca = t2.marca
WHERE t1.status=1 and isnull(t2.status,0)=0
Edit: changed join column to marca as mentioned it is for person

Related

Microsoft SQL Server - Getting latest record for value

I'm very not SQL savvy at all but I've been tasked with putting together a report for CIS benchmark test scores. I need to get the most recent score for each system without duplicates.
The system_identifier table houses the system info fields; I'm grabbing the value type 1426 (hostname)
The test_result table contains the score and date fields.
Here is my current query:
SELECT system_identifier.value AS [System Name], test_result.score + '%' AS [Most Recent Score], LEFT(MAX(test_result.upload_date), 10) AS [Test Date]
FROM system_identifier INNER JOIN test_result ON system_identifier.target_system_id = test_result.target_system_id
WHERE (system_identifier.type_id = 1426)
GROUP BY system_identifier.value, test_result.score
ORDER BY system_identifier.value
This is currently returning all records where the System Name + Score combination is unique.
System Name Most Recent Score Test Date
----------- ----------------- ---------
system1 84 2019-06-10
system1 87 2019-08-24
system1 94 2019-09-14
system2 78 2019-07-22
system2 85 2019-09-12
system3 65 2019-05-23
system3 74 2019-07-03
system3 81 2019-08-09
system3 91 2019-09-10
Here is what I need:
System Name Most Recent Score Test Date
----------- ----------------- ---------
system1 94 2019-09-14
system2 85 2019-09-12
system3 91 2019-09-10
I've tried researching this but I'm not sure how to frame my question for a search, so I thought I'd ask here since I can be more verbose with what I'm looking for.
Let me know if you need any more info.
EDIT
Neeraj's answer put me on the right track, so marking as the answer.
I ended up creating a view with the initial SELECT to put everything in one table called "merged." Then, I had success with this query (with some formatting to make it pretty):
SELECT DISTINCT
UPPER(merged.value) AS Hostname,
merged.score + '%' AS Score
LEFT(merged.upload_date,10) AS [Date Uploaded],
FROM dbo.merged
INNER JOIN (SELECT merged.value AS hostname, MAX(merged.upload_date) AS Uploaded
FROM dbo.merged
GROUP BY merged.value) t2
ON merged.value = t2.hostname
AND merged.upload_date = t2.Uploaded
WHERE merged.type_id = 1426
ORDER BY hostname
Use correlated subquery:
select t1.SystemName, t1.MostRecentScore, t1.TestDate
from myTable t1
where t1.TestDate =
(
select max(t2.TestDate)
from myTable t2
where t2.SystemName = t1.SystemName
)
Use ROW_NUMBER():
SELECT System_Name,Most_Recent_Score,Test_Date
FROM (
SELECT
t.*,
ROW_NUMBER() OVER(PARTITION BY system_name ORDER BY test_date DESC) rn
FROM mytable t
) x WHERE rn = 1
In the inner query, ROW_NUMBER() assigns a rank to each record within groups of records having the same system name, ordered by descending test date. Then the outer query selects the top record in each group.
Demo on DB Fiddle:
System_Name | Most_Recent_Score | Test_Date
:---------- | ----------------: | :------------------
system1 | 94 | 14/09/2019 00:00:00
system2 | 85 | 12/09/2019 00:00:00
system3 | 91 | 10/09/2019 00:00:00
You could also use a subquery as
WITH T AS
(
SELECT *
FROM
(
VALUES
('system1', 84, '2019-06-10'),
('system1', 87, '2019-08-24'),
('system1', 94, '2019-09-14'),
('system2', 78, '2019-07-22'),
('system2', 85, '2019-09-12'),
('system3', 65, '2019-05-23'),
('system3', 74, '2019-07-03'),
('system3', 81, '2019-08-09'),
('system3', 91, '2019-09-10')
) T(SystemName, MostRecentScore, TestDate)
)
SELECT T.*
FROM T INNER JOIN
(
SELECT SystemName,
MAX(TestDate) TestDate
FROM T
GROUP BY SystemName
) TT ON T.SystemName = TT.SystemName
AND
T.TestDate = TT.TestDate;
Online Demo

Query for replacing data if the value is not number

I have a similar problem like this thread but is bit different what it required
https://community.oracle.com/thread/4132183
I have the following table:
Table1:
ID empID employeeactive dtefrom dateto mgrid
1 123 1 1/10/2016 113
2 213 0 1/20/2015 1/20/2016 323
3 213 1 1/20/2016 423
4 312 0 1/05/2016 1/30/2017 523
5 512 1 1/30/2017 623
6 812 1 2/30/2017 6543
Table2:
empID emplyactive supid
123 1 -
213 1 -
312 1 -
512 0 -
612 1 -
712 1 -
812 1 872
912 0 222
I have this table instead of - i want to replace with mgrid in table 1.. and table2 have extra data which is not in table1 so i have to ignore the extra data if supid '-' and also want to have emplyactive =1 but some of the emplyactive=1 table 1 has multiple mgr id ...
so I tried this one
select empid , decode(supid,'-',mgrid,supid) from table2,table1 where
empid(+) = empid and emplyactive =1 and employeeactive=1
so I am getthing how to solve this please help me out thank you .. if some thing like and exists will work thanks in advance.
This is what I am trying to insert in a package body oracle.
This is how the output looks like:
empID emplyactive supid
123 1 113
213 1 423
812 1 872
select a.empid, a.emplyactive, max(a.supid) supid
from (
select * from #table2
union
select empid, employeeactive, mgrid from #table1)a
left join #table1 b on a.empid=b.empid and employeeactive=1
join #table2 c on a.empid=c.empid and c.emplyactive=1
where a.emplyactive=1
and a.supid<>0
group by a.empid, a.emplyactive

SSRS: Using exists condition in sql where clause while passing values from SSRS Parameter

Table : incident
----------------
incident_id usr_id item_id Inc_Date
10059926 191 61006 8-22-2015
10054444 222 3232 6-7-2015
Table: act_reg
--------------
act_reg_id act_type_id incident_id usr_id act_type_sc
454244 1 10059926 191 ASSIGN
471938 115 10059926 191 TRAVEL TIME
473379 40 10059926 191 FOLLOW UP
477652 115 10059926 191 TRAVEL TIME
489091 504 10059926 191 ADD_ATTCHMNTS
477653 504 10054444 222 ADD_ATTCHMNTS
Parameter: #attach (value=1, Label=Yes & Value=0, Label=No)
Result (While I am selecting 'Yes' in dropdown)
----------------------------------------------
incident_id usr_id item_id
10059926 191 61006
10054444 222 3232
My Query:
SELECT incident.incident_id,incident.usr_id,incident.item_id
FROM incident
where exists (select * from act_reg
where incident.incident_id = act_reg.incident_id
and act_reg.act_type_sc (case when #attach=1 and act_reg.act_type_sc='ADD_ATTCHMNTS' then NULL else act_reg.act_type_sc end )
)
Please help me on this.
You should change your query to the following :-
SELECT incident.incident_id,incident.usr_id,incident.item_id
FROM incident
left join act_reg
on incident.incident_id = act_reg.incident_id and act_reg.act_type_sc = 'ADD_ATTCHMNTS'
where
((#attach = 1 and act_reg.act_reg_id is not null) or
(#attach = 0 and act_reg.act_reg_id is null))
group by incident.incident_id,incident.usr_id,incident.item_id
SQL Fiddle
Here's the query that's working in SQL Fiddle with your data. I substituted the parameter with a 0.
http://www.sqlfiddle.com/#!6/7f8ef/3
SELECT incident.incident_id,incident.usr_id,incident.item_id
FROM incident
WHERE EXISTS (SELECT * from act_reg
WHERE incident.incident_id = act_reg.incident_id
AND (act_reg.act_type_sc <> 'ADD_ATTCHMNTS' OR #attach = 1)
)

Finding minimum from column value between group of rows

I have a table with six columns:
EKey ABC XYZ DOB My_Min Row_Num
---- ---- --- ---- ------ -------
101 AB10 123 1946 100 1
103 AB10 123 1946 200 2
201 TN10 456 1955 150 1
220 TN10 456 1955 240 2
216 TN10 456 1955 80 3
214 TN10 456 1955 80 4
I want to compute a new column Required_Min which should have the values as shown below:
EKey ABC XYZ DOB My_Min Row_Num Required_Min
---- ---- --- ---- ------ ------- ------------
101 AB10 123 1946 100 1 100
103 AB10 123 1946 200 2 100
201 TN10 456 1955 150 1 80
220 TN10 456 1955 240 2 80
216 TN10 456 1955 80 3 80
214 TN10 456 1955 80 4 80
Im using SQL for this, i.e., SSMS. Please help.
You can JOIN the table back to itself using the MIN aggregate:
select t.ekey, t.abc, t.xyz, t.dob, t.my_min, t.rownum,
t2.required_min
from yourtable t
join (
select ekey, min(my_min) required_min
from yourtable
group by ekey
) t2 on t.ekey = t2.ekey
If your uniqueness is based on ABC+XYZ+DOB, you can do the following:
with TableMin as
(select ABC,XYZ,DOB,min(My_min) as My_min
group by ABC,XYZ,DOB
from Table1)
update t1 set t1.Required_Min=tm.My_min
from Table1 t1 inner join TableMin tm on t1.ABC=tm.ABC and t1.XYZ=tm.XYZ and t1.DOB=tm.DOB
But this join is quite hard for server with big amount of data. If ABC+XYZ in unique key (or even ABC), use this instead of full ABC+XYZ+DOB.
This should give you the desired results:
select EKey = t.EKey ,
ABC = t.ABC ,
XYZ = t.XYZ ,
DOB = t.DOB ,
My_Min = t.My_Min ,
Row_Num = t.Row_Num ,
Required_Min = min(t.My_Min) over( partition by t.ABC , t.XYZ , t.DOB )
from dbo.my_table t
order by t.ABC ,
t.XYZ ,
t.DOB ,
t.Row_Num
If you actually want to add a new column to the table, then you'll need to do something like this:
alter table dbo.my_table add column Required_Min int null
go
update dbo.my_table
set Required_Min = s.Required_Min
from dbo.my_Table t
join ( select ABC , XYZ , DOB , Required_Min = min(My_Min)
from dbo.my_table
group by ABC , XYZ , DOB
) s on s.ABC = t.ABC
and s.XYZ = t.XYZ
and x.DOB = t.DOB
go
alter table dbo.my_table alter column Required_Min int not null
go
The update could also be standard SQL, using a correlated subquery instead of a derived table. Assuming decent indexing, the execution plans shouldn't vary too much:
update dbo.my_table
set Required_Min = ( select min(My_Min)
from dbo.my_table x
where x.ABC = dbo.my_table.ABC
and x.XYZ = dbo.my_table.XYZ
and x.DOB = dbo.my_table.DOB
)
I'm assuming ssms implies sql server. I'm assuming that you want the minimum "my_min" from rows with the same "RowNum"
try this:
update table_name as outer
set outer.Required_Min = (select min(My_Min)
from table_name as inner
where inner.RowNum = outer.RowNum)
-edit-
new assumption: ABC+XYZ+DOB form a natural key:
update table_name as outer
set outer.Required_Min = ( select min(My_Min)
from table_name as inner
where inner.ABC = outer.ABC
and inner.XYZ = outer.XYZ
and inner.DOB = outer.DOB )
Looks like a job for analitical func PARTITION BY:
select EKey, ABC, XYZ, DOB, My_Min, Row_Num,
min(My_Min) OVER (PARTITION BY ABC, XYZ, DOB) as Required_Min
from Stats
Also, I recommend you to do not store 'Required_Min' as a column, but compute it on demand in a view or query. Otherwise, you'll have to spend your time on providing data relevance (triggers or smth ). So, I would build specific inedexes instead to improve query perfomance.

Get Latest Rates For Each Distinct Rate Name

RateName Rate EffectiveDate
-------- ---- -------------
RateOne 400 2011-01-05
RateOne 410 2011-06-31
RateTwo 147 2010-09-21
RateThree 68 2011-07-14
RateTwo 100 2011-10-30
If I have data such as the above, how can I run a query such that I'll have these as results:
RateName Rate EffectiveDate
-------- ---- -------------
RateOne 410 2011-06-31
RateThree 68 2011-07-14
RateTwo 100 2011-10-30
Basically, I just need the latest rates for each distinct rate name.
You can try this:
SELECT A.*
FROM YourTable A
INNER JOIN ( SELECT RateName, MAX(EffectiveDate) AS MaxDate
FROM YourTable
GROUP BY RateName) B
ON A.RateName = B.RateName AND A.EffectiveDate = B.MaxDate