I have data like this :
end date billing
30-NOV-16 0
31-DEC-16 0
31-JAN-17 0
28-FEB-17 208200
31-MAR-17 362950
and when I run this query :
SELECT *
FROM
(SELECT
ps.end_date end_date
, ps.itd_gross_billing billing
FROM project_summary_v ps
JOIN projects_dtl pd ON ps.project_id=pd.project_id
JOIN periods_dim xpd ON ps.end_date=xpd.end_date
WHERE pd.project_number=100
FETCH FIRST 6 rows only
)
PIVOT
(
max(billing)
FOR end_date in ( '31-OCT-16'
,'30-NOV-16'
,'31-DEC-16'
,'31-JAN-17'
,'28-FEB-17'
,'31-MAR-17' )
);
I get the following output
31-OCT-16 30-NOV-16 31-DEC-16 31-JAN-17 28-FEB-17 31-MAR-17
0 0 0 0 208200 362950
All good so far. But when I have few more columns data,
end date billing pd_data mn_data
31-OCT-16 0 10 1
30-NOV-16 0 100 2
31-DEC-16 0 200 3
31-JAN-17 0 90 4
28-FEB-17 208200 30 5
31-MAR-17 362950 50 6
How to transpose this table ? Also if the end date is dynamic ( as of now I have hard coded )- What should be the query inside the in ( ) .
Output should be something like this :
31-OCT-16 30-NOV-16 31-DEC-16 31-JAN-17 28-FEB-17 31-MAR-17
billing 0 0 0 0 208200 362950
pd_data 10 100 200 90 30 50
mn_data 1 2 3 4 5 6
I think the below query would work. I have separated the queries to pivot. Hope this helps.
SELECT *
FROM
(SELECT ps.end_date end_date ,
ps.itd_gross_billing billing
FROM project_summary_v ps
JOIN projects_dtl pd
ON ps.project_id=pd.project_id
JOIN periods_dim xpd
ON ps.end_date =xpd.end_date
WHERE pd.project_number=100
FETCH FIRST 6 rows only
) pivot( MAX(billing) FOR end_date IN ( '31-OCT-16' ,'30-NOV-16' ,'31-DEC-16' ,'31-JAN-17' ,'28-FEB-17' ,'31-MAR-17' ) )
UNION ALL
SELECT *
FROM
(SELECT ps.end_date end_date ,
ps.pd_data pd_data
FROM project_summary_v ps
JOIN projects_dtl pd
ON ps.project_id=pd.project_id
JOIN periods_dim xpd
ON ps.end_date =xpd.end_date
WHERE pd.project_number=100
FETCH FIRST 6 rows only
) pivot( MAX(pd_data) FOR end_date IN ( '31-OCT-16' ,'30-NOV-16' ,'31-DEC-16' ,'31-JAN-17' ,'28-FEB-17' ,'31-MAR-17' ) )
UNION ALL
SELECT *
FROM
(SELECT ps.end_date end_date ,
ps.mn_data mn_data
FROM project_summary_v ps
JOIN projects_dtl pd
ON ps.project_id=pd.project_id
JOIN periods_dim xpd
ON ps.end_date =xpd.end_date
WHERE pd.project_number=100
FETCH FIRST 6 rows only
) pivot( MAX(mn_data) FOR end_date IN ( '31-OCT-16' ,'30-NOV-16' ,'31-DEC-16' ,'31-JAN-17' ,'28-FEB-17' ,'31-MAR-17' ) )
Related
I need to create a report and I am struggling with the SQL script.
The table I want to query is a company_status_history table which has entries like the following (the ones that I can't figure out)
Table company_status_history
Columns:
| id | company_id | status_id | effective_date |
Data:
| 1 | 10 | 1 | 2016-12-30 00:00:00.000 |
| 2 | 10 | 5 | 2017-02-04 00:00:00.000 |
| 3 | 11 | 5 | 2017-06-05 00:00:00.000 |
| 4 | 11 | 1 | 2018-04-30 00:00:00.000 |
I want to answer to the question "Get all companies that have been at least for some point in status 1 inside the time period 01/01/2017 - 31/12/2017"
Above are the cases that I don't know how to handle since I need to add some logic of type :
"If this row is status 1 and it's date is before the date range check the next row if it has a date inside the date range."
"If this row is status 1 and it's date is after the date range check the row before if it has a date inside the date range."
I think this can be handled as a gaps and islands problem. Consider the following input data: (same as sample data of OP plus two additional rows)
id company_id status_id effective_date
-------------------------------------------
1 10 1 2016-12-15
2 10 1 2016-12-30
3 10 5 2017-02-04
4 10 4 2017-02-08
5 11 5 2017-06-05
6 11 1 2018-04-30
You can use the following query:
SELECT t.id, t.company_id, t.status_id, t.effective_date, x.cnt
FROM company_status_history AS t
OUTER APPLY
(
SELECT COUNT(*) AS cnt
FROM company_status_history AS c
WHERE c.status_id = 1
AND c.company_id = t.company_id
AND c.effective_date < t.effective_date
) AS x
ORDER BY company_id, effective_date
to get:
id company_id status_id effective_date grp
-----------------------------------------------
1 10 1 2016-12-15 0
2 10 1 2016-12-30 1
3 10 5 2017-02-04 2
4 10 4 2017-02-08 2
5 11 5 2017-06-05 0
6 11 1 2018-04-30 0
Now you can identify status = 1 islands using:
;WITH CTE AS
(
SELECT t.id, t.company_id, t.status_id, t.effective_date, x.cnt
FROM company_status_history AS t
OUTER APPLY
(
SELECT COUNT(*) AS cnt
FROM company_status_history AS c
WHERE c.status_id = 1
AND c.company_id = t.company_id
AND c.effective_date < t.effective_date
) AS x
)
SELECT id, company_id, status_id, effective_date,
ROW_NUMBER() OVER (PARTITION BY company_id ORDER BY effective_date) -
cnt AS grp
FROM CTE
Output:
id company_id status_id effective_date grp
-----------------------------------------------
1 10 1 2016-12-15 1
2 10 1 2016-12-30 1
3 10 5 2017-02-04 1
4 10 4 2017-02-08 2
5 11 5 2017-06-05 1
6 11 1 2018-04-30 2
Calculated field grp will help us identify those islands:
;WITH CTE AS
(
SELECT t.id, t.company_id, t.status_id, t.effective_date, x.cnt
FROM company_status_history AS t
OUTER APPLY
(
SELECT COUNT(*) AS cnt
FROM company_status_history AS c
WHERE c.status_id = 1
AND c.company_id = t.company_id
AND c.effective_date < t.effective_date
) AS x
), CTE2 AS
(
SELECT id, company_id, status_id, effective_date,
ROW_NUMBER() OVER (PARTITION BY company_id ORDER BY effective_date) -
cnt AS grp
FROM CTE
)
SELECT company_id,
MIN(effective_date) AS start_date,
CASE
WHEN COUNT(*) > 1 THEN DATEADD(DAY, -1, MAX(effective_date))
ELSE MIN(effective_date)
END AS end_date
FROM CTE2
GROUP BY company_id, grp
HAVING COUNT(CASE WHEN status_id = 1 THEN 1 END) > 0
Output:
company_id start_date end_date
-----------------------------------
10 2016-12-15 2017-02-03
11 2018-04-30 2018-04-30
All you want know is those records from above that overlap with the specified interval.
Demo here with somewhat more complicated use case.
Maybe this is what you are looking for? For these kind of questions, you need to join two instance of your table, in this case I am just joining with next record by Id, which probably is not totally correct. To do it better, you can create a new Id using a windowed function like row_number, ordering the table by your requirement criteria
If this row is status 1 and it's date is before the date range check
the next row if it has a date inside the date range
declare #range_st date = '2017-01-01'
declare #range_en date = '2017-12-31'
select
case
when csh1.status_id=1 and csh1.effective_date<#range_st
then
case
when csh2.effective_date between #range_st and #range_en then true
else false
end
else NULL
end
from company_status_history csh1
left join company_status_history csh2
on csh1.id=csh2.id+1
Implementing second criteria:
"If this row is status 1 and it's date is after the date range check
the row before if it has a date inside the date range."
declare #range_st date = '2017-01-01'
declare #range_en date = '2017-12-31'
select
case
when csh1.status_id=1 and csh1.effective_date<#range_st
then
case
when csh2.effective_date between #range_st and #range_en then true
else false
end
when csh1.status_id=1 and csh1.effective_date>#range_en
then
case
when csh3.effective_date between #range_st and #range_en then true
else false
end
else null -- ¿?
end
from company_status_history csh1
left join company_status_history csh2
on csh1.id=csh2.id+1
left join company_status_history csh3
on csh1.id=csh3.id-1
I would suggest the use of a cte and the window functions ROW_NUMBER. With this you can find the desired records. An example:
DECLARE #t TABLE(
id INT
,company_id INT
,status_id INT
,effective_date DATETIME
)
INSERT INTO #t VALUES
(1, 10, 1, '2016-12-30 00:00:00.000')
,(2, 10, 5, '2017-02-04 00:00:00.000')
,(3, 11, 5, '2017-06-05 00:00:00.000')
,(4, 11, 1, '2018-04-30 00:00:00.000')
DECLARE #StartDate DATETIME = '2017-01-01';
DECLARE #EndDate DATETIME = '2017-12-31';
WITH cte AS(
SELECT *
,ROW_NUMBER() OVER (PARTITION BY company_id ORDER BY effective_date) AS rn
FROM #t
),
cteLeadLag AS(
SELECT c.*, ISNULL(c2.effective_date, c.effective_date) LagEffective, ISNULL(c3.effective_date, c.effective_date)LeadEffective
FROM cte c
LEFT JOIN cte c2 ON c2.company_id = c.company_id AND c2.rn = c.rn-1
LEFT JOIN cte c3 ON c3.company_id = c.company_id AND c3.rn = c.rn+1
)
SELECT 'Included' AS RangeStatus, *
FROM cteLeadLag
WHERE status_id = 1
AND effective_date BETWEEN #StartDate AND #EndDate
UNION ALL
SELECT 'Following' AS RangeStatus, *
FROM cteLeadLag
WHERE status_id = 1
AND effective_date > #EndDate
AND LagEffective BETWEEN #StartDate AND #EndDate
UNION ALL
SELECT 'Trailing' AS RangeStatus, *
FROM cteLeadLag
WHERE status_id = 1
AND effective_date < #EndDate
AND LeadEffective BETWEEN #StartDate AND #EndDate
I first select all records with their leading and lagging Dates and then I perform your checks on the inclusion in the desired timespan.
Try with this, self-explanatory. Responds to this part of your question:
I want to answer to the question "Get all companies that have been at
least for some point in status 1 inside the time period 01/01/2017 -
31/12/2017"
Case that you want to find those id's that have been in any moment in status 1 and have records in the period requested:
SELECT *
FROM company_status_history
WHERE id IN
( SELECT Id
FROM company_status_history
WHERE status_id=1 )
AND effective_date BETWEEN '2017-01-01' AND '2017-12-31'
Case that you want to find id's in status 1 and inside the period:
SELECT *
FROM company_status_history
WHERE status_id=1
AND effective_date BETWEEN '2017-01-01' AND '2017-12-31'
I am extracting data out of SQL database and need to calculate the opening balance of a stock item per project. I am getting the opening balance for the stock inclusive of all the projects.
item code | Project | Qty In | Qty Out
----------+---------+--------+---------
1234 1 0 90
1234 1 90 0
1234 2 431 0
1234 2 0 22
1234 3 925 0
1234 3 0 925
1234 3 925 0
1234 3 0 20
1234 3 0 40
1234 3 0 30
1234 3 0 40
1234 3 0 60
1234 3 0 50
1234 3 0 24
1234 3 0 40
1234 3 0 30
1234 3 0 17
1234 3 0 80
1234 3 0 30
1234 4 16 0
1234 4 0 16
1234 5 22 0
1234 5 0 23
Query:
select OpeningBalanceQty = Qty_On_Hand +
(select case when ServiceItem = 0
then IsNull(sum (QtyOut), 0)
else 0
end
from table1
where AccountLink=StockLink and txdate>='2016-06-01' and project ='2' ) -
(select case when ServiceItem = 0
then IsNull(sum (QtyIn), 0)
else 0
end from table1
where AccountLink=StockLink and txdate>='2016-06-01' and project ='2')
from tablel join table2 on table1.AccountLink = table2.StockLink
I have used project 2 as an example, it has two transactions(qty in:431)& (qty out:22)
My opening balance should be 409 but it is giving the total for the product item
My full code:
select Table1.TxDate,Table2.Pack,Table1.Reference,
OpeningBalanceQty= (select case when ServiceItem = 0 then IsNull(sum
(QtyOut), 0) else 0 end from Table1 where AccountLink=StockLink and
ProjectCode in('2') ) - (select case when ServiceItem = 0 then IsNull(sum
(QtyIn), 0) else 0 end from Table1 where AccountLink=StockLink and
ProjectCode in('2'))
,ProjectCode,ProjectDescription, Code, Description_1, Sum(ActualQuantity)*-1
as [Qty Processed],Sum(Debit)-Sum(Credit) as [Value],Trcode
from Table1
join Table2
on Table1 .AccountLink = Table2.StockLink
where ServiceItem = 0 and txdate>='2017-06-01 00:00:00' and txdate<='2017-
06-30 00:00:00' and Code='1234'
Group by Description_1, Code,ProjectCode, ProjectDescription, stocklink,
serviceitem,Qty_On_Hand,Table1.Reference,Table2.Pack,Table1.TxDate,trcode
Do you think this could be helpful for you?
SELECT PROJECT, SUM( QTYIN-QTYOUT) AS OPEN_BAL_QTY
FROM yourtable
WHERE txdate>='2016-06-01'
GROUP BY PROJECT
Output:
PROJECT OPEN_BAL_QTY
1 0
2 409
3 464
4 0
5 -1
1° update: after your new information (pls, next time, try to give all the information in your initial post, and well formatted: see tour of stackoverflow to learn how to do).
If you are using MSSQL 2005 or later, you can try this:
SELECT TABLE1.TXDATE
,TABLE2.PACK
,TABLE1.REFERENCE
, SUM(QTYIN-QTYOUT) OVER (PARTITION BY TABLE1.PROJECTCODE) AS OPEN_BAL_QTY
,PROJECTCODE
,PROJECTDESCRIPTION
,CODE
,DESCRIPTION_1
,-SUM(ACTUALQUANTITY) AS QTY PROCESSED
, SUM(DEBIT) - SUM(CREDIT) AS VALUE
,TRCODE
FROM TABLE1
JOIN TABLE2 ON TABLE1.ACCOUNTLINK = TABLE2.STOCKLINK
WHERE SERVICEITEM = 0
AND TXDATE >= '2017-06-01 00:00:00'
AND TXDATE <= '2017-06-30 00:00:00'
AND CODE = '1234'
GROUP BY DESCRIPTION_1
,CODE
,PROJECTCODE
,PROJECTDESCRIPTION
,STOCKLINK
,SERVICEITEM
,QTY_ON_HAND
,TABLE1.REFERENCE
,TABLE2.PACK
,TABLE1.TXDATE
,TRCODE
2° update
If it doesn't work for you, you should try:
SELECT A.*
,B.OPEN_BAL_QTY
FROM
SELECT TABLE1.TXDATE
,TABLE2.PACK
,TABLE1.REFERENCE
,PROJECTCODE
,PROJECTDESCRIPTION
,CODE
,DESCRIPTION_1
,-SUM(ACTUALQUANTITY) AS QTY PROCESSED
, SUM(DEBIT) - SUM(CREDIT) AS VALUE
,TRCODE
FROM TABLE1
JOIN TABLE2 ON TABLE1.ACCOUNTLINK = TABLE2.STOCKLINK
WHERE SERVICEITEM = 0
AND TXDATE >= '2017-06-01 00:00:00'
AND TXDATE <= '2017-06-30 00:00:00'
AND CODE = '1234'
GROUP BY DESCRIPTION_1
,CODE
,PROJECTCODE
,PROJECTDESCRIPTION
,STOCKLINK
,SERVICEITEM
,QTY_ON_HAND
,TABLE1.REFERENCE
,TABLE2.PACK
,TABLE1.TXDATE
,TRCODE
) A
LEFT JOIN (SELECT PROJECTCODE, SUM( QTYIN-QTYOUT) AS OPEN_BAL_QTY
FROM TABLE1
WHERE TXDATE>='2017-06-01'
AND TXDATE <= '2017-06-30 00:00:00'
GROUP BY PROJECT) B ON A.PROJECT_CODE = B.PROJECT_CODE
I have three tables which are like:
table1
id,
created_Date
table2
id
district_ID
status_ID
table3
district_ID
district_Name
Now i need the records in following format
Srno District_name <10 days >10 and <20 days >20 days
1 xxx 12 15 20
2 yyy 8 0 2
count days as per current date
for example: if the created date is 10-08-2013 and current date is 13-08-2013 the date difference will be 3
So what should my query be? Any suggestions will be appreciated.
Thank you
table1
id created_Date
1 2013-07-12 13:32:10.957
2 2013-07-12 13:32:10.957
3 2013-08-01 10:00:10.957
4 2013-08-10 13:32:10.957
5 2013-08-10 14:32:10.957
table2
id district_ID status_id
1 1 3
2 2 3
3 2 7
4 3 4
5 4 3
table1
district_ID district_Name
1 xxx
2 yyy
3 zzz
4 aaa
5 bbb
I would have a look at using DATEDIFF and CASE.
DATEDIFF (Transact-SQL)
Returns the count (signed integer) of the specified datepart
boundaries crossed between the specified startdate and enddate.
Something like
SELECT District_name,
SUM(
CASE
WHEN DATEDIFF(day,created_Date, getdate()) < 10
THEN 1
ELSE 0
END
) [<10 days],
SUM(
CASE
WHEN DATEDIFF(day,created_Date, getdate()) >= 10 AND DATEDIFF(day,created_Date, getdate()) < 20
THEN 1
ELSE 0
END
) [>10 and <20 days],
SUM(
CASE
WHEN DATEDIFF(day,created_Date, getdate()) >= 20
THEN 1
ELSE 0
END
) [>20 days]
FROM Your_Tables_Here
GROUP BY District_name
;with cte as (
select t3.district_Name, datediff(day, t1.created_Date, getdate()) as diff
from table1 as t1 as t1
inner join table2 as t2 on t2.id = t1.id
inner join table3 as t3 on t3.district_id = t2.district_id
)
select
district_Name,
sum(case when diff < 10 then 1 else 0 end) as [<10 days],
sum(case when diff >= 10 and diff < 20 then 1 else 0 end) as [>=10 and < 20 days],
sum(case when diff >= 20 then 1 else 0 end) as [>= 20 days]
from cte
group by district_Name
I'm stuck with a seemingly easy query, but couldn't manage to get it working the last hours.
I have a table files that holds file names and some values like records in this file, DATE of creation (create_date), DATE of processing (processing_date) and so on. There can be multiple files for a create date in different hours and it is likely that they will not get processed in the same day of creaton, in fact it can even take up to three days or longer for them to get processed.
So let's assume I have these rows, as an example:
create_date | processing_date
------------------------------
2012-09-10 11:10:55.0 | 2012-09-11 18:00:18.0
2012-09-10 15:20:18.0 | 2012-09-11 13:38:19.0
2012-09-10 19:30:48.0 | 2012-09-12 10:59:00.0
2012-09-11 08:19:11.0 | 2012-09-11 18:14:44.0
2012-09-11 22:31:42.0 | 2012-09-21 03:51:09.0
What I want in a single query is to get a grouped column truncated to the day create_date with 11 additional columns for the differences between the processing_date and the create_date, so that the result should roughly look like this:
create_date | diff0days | diff1days | diff2days | ... | diff10days
------------------------------------------------------------------------
2012-09-10 | 0 2 1 ... 0
2012-09-11 | 1 0 0 ... 1
and so on, I hope you get the point :)
I have tried this and so far it works getting a single aggregated column for a create_date with a difference of - for example - 3:
SELECT TRUNC(f.create_date, 'DD') as created, count(1) FROM files f WHERE TRUNC(f.process_date, 'DD') - trunc(f.create_date, 'DD') = 3 GROUP BY TRUNC(f.create_date, 'DD')
I tried combining the single queries and I tried sub-queries, but that didn't help or at least my knowledge about SQL is not sufficient.
What I need is a hint so that I can include the various differences as columns, like shown above. How could I possibly achieve this?
That's basically the pivoting problem:
SELECT TRUNC(f.create_date, 'DD') as created
, sum(case TRUNC(f.process_date, 'DD') - trunc(f.create_date, 'DD')
when 0 then 1 end) as diff0days
, sum(case TRUNC(f.process_date, 'DD') - trunc(f.create_date, 'DD')
when 1 then 1 end) as diff1days
, sum(case TRUNC(f.process_date, 'DD') - trunc(f.create_date, 'DD')
when 2 then 1 end) as diff2days
, ...
FROM files f
GROUP BY
TRUNC(f.create_date, 'DD')
SELECT CreateDate,
sum(CASE WHEN DateDiff(day, CreateDate, ProcessDate) = 1 THEN 1 ELSE 0 END) AS Diff1,
sum(CASE WHEN DateDiff(day, CreateDate, ProcessDate) = 2 THEN 1 ELSE 0 END) AS Diff2,
...
FROM table
GROUP BY CreateDate
ORDER BY CreateDate
As you are using Oracle 11g you can also get desired result by using pivot query.
Here is an example:
-- sample of data from your question
SQL> create table Your_table(create_date, processing_date) as
2 (
3 select '2012-09-10', '2012-09-11' from dual union all
4 select '2012-09-10', '2012-09-11' from dual union all
5 select '2012-09-10', '2012-09-12' from dual union all
6 select '2012-09-11', '2012-09-11' from dual union all
7 select '2012-09-11', '2012-09-21' from dual
8 )
9 ;
Table created
SQL> with t2 as(
2 select create_date
3 , processing_date
4 , to_date(processing_date, 'YYYY-MM-DD')
- To_Date(create_date, 'YYYY-MM-DD') dif
5 from your_table
6 )
7 select create_date
8 , max(diff0) diff0
9 , max(diff1) diff1
10 , max(diff2) diff2
11 , max(diff3) diff3
12 , max(diff4) diff4
13 , max(diff5) diff5
14 , max(diff6) diff6
15 , max(diff7) diff7
16 , max(diff8) diff8
17 , max(diff9) diff9
18 , max(diff10) diff10
19 from (select *
20 from t2
21 pivot(
22 count(dif)
23 for dif in ( 0 diff0
24 , 1 diff1
25 , 2 diff2
26 , 3 diff3
27 , 4 diff4
28 , 5 diff5
29 , 6 diff6
30 , 7 diff7
31 , 8 diff8
32 , 9 diff9
33 , 10 diff10
34 )
35 ) pd
36 ) res
37 group by create_date
38 ;
Result:
Create_Date Diff0 Diff1 Diff2 Diff3 Diff4 Diff5 Diff6 Diff7 Diff8 Diff9 Diff10
--------------------------------------------------------------------------------
2012-09-10 0 2 1 0 0 0 0 0 0 0 0
2012-09-11 1 0 0 0 0 0 0 0 0 0 1
I am making a payroll system and I bought the B3 tft from zktechnology and would like to arrange the record.
Currently I can pull the data from the biometric with this format:
Count EmpID InOutMode Date
1 1 0 8/20/2012 07:49:01
2 1 1 8/20/2012 12:08:21
3 1 0 8/20/2012 12:43:10
4 1 1 8/20/2012 17:56:15
5 2 0 8/20/2012 07:53:11
6 2 1 8/20/2012 12:02:01
7 2 0 8/20/2012 12:39:56
8 2 1 8/20/2012 17:20:43
9 1 0 8/21/2012 08:10:20
10 1 1 8/21/2012 12:01:26
11 1 0 8/21/2012 13:03:11
12 1 1 8/21/2012 17:11:15
13 2 0 8/21/2012 07:48:26
14 2 1 8/21/2012 12:14:58
15 2 0 8/21/2012 12:59:31
16 2 1 8/21/2012 17:20:12
InOutMode:
0 = In, 1 = Out
Now, I want to convert the data above like this:
EmpID Date AM_In AM_Out PM_In PM_Out
1 8/20/2012 07:49:01 12:08:21 12:43:10 17:56:15
2 8/20/2012 07:53:11 12:02:01 12:39:56 17:20:43
1 8/21/2012 08:10:20 12:01:26 13:03:11 17:11:15
2 8/21/2012 07:48:26 12:14:58 12:59:31 17:20:12
So I can save it to the database with EmpID, Date, AM_In, AM_Out, PM_In, PM_Out fields.
I saw a similar code here before but I can't remember the URL.
Update:
VB.net code or sql in ms access format is acceptable.
It might be easiest to create two cross tabs and a query to join them to the available dates and employees.
1 AM Crosstab
TRANSFORM Min(tm.Date) AS MinOfDate
SELECT Format([Date],"dd/mm/yyyy") AS dt, tm.EmpID
FROM tm
GROUP BY Format([Date],"dd/mm/yyyy"), tm.EmpID
PIVOT tm.InOutMode;
2 PM Crosstab
TRANSFORM Max(tm.Date) AS MinOfDate
SELECT Format([Date],"dd/mm/yyyy") AS dt, tm.EmpID
FROM tm
GROUP BY Format([Date],"dd/mm/yyyy"), tm.EmpID
PIVOT tm.InOutMode;
Where tm is the name of your table.
You can then join these up.
SELECT Alldates.dt,
Alldates.empid,
am.[0] AS [Am In],
am.[1] AS [Am Out],
pm.[0] AS [Pm In],
pm.[1] AS [Pm Out]
FROM ((SELECT DISTINCT Format([date], "dd/mm/yyyy") AS dt,
empid
FROM tm) AS Alldates
LEFT JOIN am
ON ( Alldates.empid = am.empid )
AND ( Alldates.dt = am.dt ))
LEFT JOIN pm
ON ( Alldates.empid = pm.empid )
AND ( Alldates.dt = pm.dt );
Here is a query that should produce the results that you want in MS Access:
select am_in.empid,
format(am_in.min_in_dt, "MM/DD/YYYY") as [date],
format(am_in.min_in_dt, "hh:mm:ss") as AM_In,
format(am_out.min_out_dt, "hh:mm:ss") as AM_Out,
format(pm_in.max_in_dt, "hh:mm:ss") as PM_In,
format(pm_out.max_out_dt, "hh:mm:ss") as PM_Out
from
(
(
(
SELECT empid,
min(dt) as min_in_dt
FROM yourTable
where inoutmode = 0
group by empid
) am_in
inner join
(
SELECT empid,
min(dt) as min_out_dt
FROM yourTable
where inoutmode = 1
group by empid
) am_out
on am_in.empid = am_out.empid
)
inner join
(
SELECT empid,
max(dt) as max_in_dt
FROM yourTable
where inoutmode = 0
group by empid
) pm_in
on am_in.empid = pm_in.empid
)
inner join
(
SELECT empid,
max(dt) as max_out_dt
FROM yourTable
where inoutmode = 1
group by empid
) pm_out
on am_in.empid = pm_out.empid
Something like this will work
select
empid,
dateadd(day,datediff(day,0,DATE),0) as date,
max(case when sno=1 then convert(varchar(8),DATE,108)) as AM_IN,
max(case when sno=2 then convert(varchar(8),DATE,108)) as AM_OUT,
max(case when sno=3 then convert(varchar(8),DATE,108)) as PM_IN,
max(case when sno=4 then convert(varchar(8),DATE,108)) as PM_OUT
from
(
select *,
row_number() over (partition by empid order by Empid) as sno
from
table
) as t
group by
empid,dateadd(day,datediff(day,0,DATE),0)