How to use MIN, IFF and Datepart functions together in MS ACCESS? - sql

I have a table like below, I want to group date time entries based on date without time and shifts for example, morning shift starts at 5 AM and ends at 14 PM. Here, MAX function finds the correct date, could you help me to see what's wrong with MIN function?
Indate Incondition
--------- -----------
25.01.2013 05:00:38 KT-RING
25.01.2013 05:21:52 KT-EMPTY
25.01.2013 05:22:00 KT-PROCESS
25.01.2013 06:10:50 KT-RING
25.01.2013 16:10:50 KT-EMPTY
26.01.2013 06:10:50 KT-RING
SELECT Int(Indate) AS DATE,
Min( IIf( ( DatePart('h',[Indate])>=05 AND DatePart('h', [Indate])<13), Indate, 0)) AS FRUHRINGMIN,
Max(IIf((DatePart('h',Indate)>=05 And
DatePart('h',Indate)<13), Indate,0)) AS FRUHRINGMAX
FROM TABLE WHERE Incondition= 'KT-RING'
GROUP BY Int(Indate);
RESULT:
DATE FRUHRINGMIN FRUHRINGMAX
----- ------------- -----------
25.01.2013 00:00:00 25.01.2013 06:10:50
26.01.2013 00:00:00 26.01.2013 06:10:50

I saved your sample data in a table in my Access 2007 database. But when I attempted to run your query, Access threw an error about the alias DATE, which is a reserved word. Bracketing that alias allowed the query to run without error.
SELECT
Int(Indate) AS [DATE],
Min(IIf((DatePart('h',[Indate])>=05 AND DatePart('h', [Indate])<13), Indate, 0)) AS FRUHRINGMIN,
Max(IIf((DatePart('h',Indate)>=05 And DatePart('h',Indate)<13), Indate,0)) AS FRUHRINGMAX
FROM tblJeanneQuadel
WHERE Incondition= 'KT-RING'
GROUP BY Int(Indate);
However the results it gave me did not match what you reported.
DATE FRUHRINGMIN FRUHRINGMAX
41299 1/25/2013 5:00:38 AM 1/25/2013 6:10:50 AM
41300 1/26/2013 6:10:50 AM 1/26/2013 6:10:50 AM
Note my Date/Time values are in US format, but they're actually based on the same values as yours, just displayed differently.
I don't understand why your query result displayed the first column as a date rather than a long integer as mine did and which I would expect as the result from Int(Indate). But that's a minor point; we can convert from one to the other if needed.
More importantly, I'm unsure about what's actually going on. If bracketing [DATE] does not allow your query to run and produce the correct results, try moving the IIf() condition into the WHERE clause. That would greatly simplify your Min() and Max() expressions. But if that still doesn't produce exactly the results you want, show us what it does return and what you want returned instead.

Related

SELECT MIN from a subset of data obtained through GROUP BY

There is a database in place with hourly timeseries data, where every row in the DB represents one hour. Example:
TIMESERIES TABLE
id date_and_time entry_category
1 2017/01/20 12:00 type_1
2 2017/01/20 13:00 type_1
3 2017/01/20 12:00 type_2
4 2017/01/20 12:00 type_3
First I used the GROUP BY statement to find the latest date and time for each type of entry category:
SELECT MAX(date_and_time), entry_category
FROM timeseries_table
GROUP BY entry_category;
However now, I want to find which is the date and time which is the LEAST RECENT among the datetime's I obtained with the query listed above. I will need to use somehow SELECT MIN(date_and_time), but how do I let SQL know I want to treat the output of my previous query as a "new table" to apply a new SELECT query on? The output of my total query should be a single value—in case of the sample displayed above, date_and_time = 2017/01/20 12:00.
I've tried using aliases, but don't seem to be able to do the trick, they only rename existing columns or tables (or I'm misusing them..).There are many questions out there that try to list the MAX or MIN for a particular group (e.g. https://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/ or Select max value of each group) which is what I have already achieved, but I want to do work now on this list of obtained datetime's. My database structure is very simple, but I lack the knowledge to string these queries together.
Thanks, cheers!
You can use your first query as a sub-query, it is similar to what you are describing as using the first query's output as the input for the second query. Here you will get the one row out put of the min date as required.
SELECT MIN(date_and_time)
FROM (SELECT MAX(date_and_time) as date_and_time, entry_category
FROM timeseries_table
GROUP BY entry_category)a;
Is this what you want?
SELECT TOP 1 MAX(date_and_time), entry_category
FROM timeseries_table
GROUP BY entry_category
ORDER BY MAX(date_and_time) ASC;
This returns ties. If you do not want ties, then include an additional sort key:
SELECT TOP 1 MAX(date_and_time), entry_category
FROM timeseries_table
GROUP BY entry_category
ORDER BY MAX(date_and_time) ASC, entry_category;

Sort by / Order by time stored in database "00:00 - 23:00"

I'm trying to figure out an sql query that would allow me to sort data ascending order depending on what time is sorted in appointment_time column, it has values like "00:00" - "23:00"
In my head it looks like this:
SELECT * FROM myTable ORDER BY appointment_time ASC
But I don't know how to make it understand that 00:00 is lower value than 00:01 for example and so on.
They will sort fine as your query is written, easiest thing is to just give it a whirl and see what happens:
SELECT *
FROM myTable
ORDER BY appointment_time ASC
Demo: SQL Fiddle
Alphanumeric ordering has no problem with numbers stored in strings so long as they are zero padded, as is the case with your times.
But I don't know how to make it understand that 00:00 is lower value than 00:01
If all you have is a time then an alphabetical sort should work just fine. If you want to convert to a DateTime you can use CONVERT:
select CONVERT(DATETIME, appointment_time , 108)
If you store from_time and to_time as DATETIME (in two separate columns), the sorting will be done correctly by the DB.
It will also take into consideration the date part as well, i.e. sort 1 Jan 2014 23:00 before 31 Dec 2013 23:30. If you really aren't interested in the date, use a dummy date for all entries and just use the time part of the column.

Oracle date column showing the wrong value

I'm trying to identify a problem in a date colum in my table.
The database is Oracle 11g.
The situation is:
When I run the following query:
select to_char(data_val, 'DD/MM/YYYY'), a.data_val from material a order by a.data_val asc;
the five first lines of the result are:
00/00/0000 | 29/06/5585 00:00:00
00/00/0000 | 29/06/5585 00:00:00
00/00/0000 | 29/06/5585 00:00:00
11/11/1111 | 11/11/1111 00:00:00
01/01/1500 | 01/01/1500 00:00:00
the question is:
Why the to_char function of the first three lines returns a different value of date (00/00/0000)?
And why the date 29/06/5585 is the first result of a ASC date order by? It'll be right using: order by data_val DESC, will not?
We've encountered the same problem. I can confirm that the "date" column is indeed the DATE type.
The date in question is 01-May-2014, so it's most likely not related to the big year number in the original post. And when you perform some calculation with the date, the problem is fixed, i.e. TO_CHAR(datum) would be all zeros, TO_CHAR(datum + 1) would be as expected, and even TO_CHAR(datum +1 -1) would be correct. (TO_CHAR(datum+0) doesn't help :))
Based on the DUMP value it seems that the problem is that we've somehow managed to store 31-Apr-2014 rather than 01-May-2014 (investigating now how that was possible; Informatica + Oracle 11.2, I believe).

SQL working days query

I am trying to write a query to calculate the number of working days between 2 dates. I first tried this in VBA, which worked, but this is not very efficient.
I have 2 queries, the first works out the date difference between a valueDate and cutOffDate; the second counts the number of dates from a table of holidays/weekends that fall between the valueDate and cutOffDay.
The trouble I'm having is how to combine these 2 parts to give the item age (number of working days between the dates).
My query examples are:
SELECT allOS.SortCode, allOS.NPA, allOS.valueDate, allOS.cutOffDate,
DateDiff("d",[allOS.valueDate],[allOS.cutOffDate]) AS Age
FROM allOS;
and
SELECT Count(Holidays.Holiday) AS NonWorkingDays
FROM Holidays
HAVING (([Holiday]>[#01/01/2013#] And [Holiday]<[#11/06/2013#]));
I need to subtract the result of the second query from the Age of the first query.
Sample input and output data
allOS:
sortCode|npa|valueDate|cutOffDate
111111|99999999|01-11-2013|15-11-2013
222222|77777777|04-11-2013|15-11-2013
333333|88888888|05-11-2013|15-11-2013
444444|66666666|06-11-2013|15-11-2013
555555|44444444|07-11-2013|15-11-2013
666666|33333333|12-11-2013|15-11-2013
777777|55555555|13-11-2013|15-11-2013
888888|11111111|14-11-2013|15-11-2013
999999|22222222|15-11-2013|15-11-2013
Holidays:
holiday|reason
02-11-2013|Saturday
03-11-2013|Sunday
08-11-2013|Long Weekend
09-11-2013|Saturday
10-11-2013|Sunday
11-11-2013|Long Weekend
16-11-2013|Saturday
17-11-2013|Sunday`
Result:
sortCode|npa|valueDate|cutOffDate|Age
111111|99999999|01-11-2013|15-11-2013|8
222222|77777777|04-11-2013|15-11-2013|7
333333|88888888|05-11-2013|15-11-2013|6
444444|66666666|06-11-2013|15-11-2013|5
555555|44444444|07-11-2013|15-11-2013|4
666666|33333333|12-11-2013|15-11-2013|3
777777|55555555|13-11-2013|15-11-2013|2
888888|11111111|14-11-2013|15-11-2013|1
999999|22222222|15-11-2013|15-11-2013|0
The results for age is the difference between the valueDate and cutOffDate less any of the days from the holiday table.
You can use a correlated subquery to calculate the number of non-work days included in each valueDate and cutOffDate date range.
Here is a preliminary query I tested with your sample data, and I included the first and last rows output from that query.
SELECT
a.sortCode,
a.npa,
a.valueDate,
a.cutOffDate,
DateDiff('d', a.valueDate, a.cutOffDate) AS raw_days,
(
SELECT Count(*)
FROM Holidays
WHERE holiday BETWEEN a.valueDate AND a.cutOffDate
) AS NonWorkDays
FROM allOS AS a;
sortCode npa valueDate cutOffDate raw_days NonWorkDays
-------- -------- ---------- ---------- -------- -----------
111111 99999999 11/1/2013 11/15/2013 14 6
999999 22222222 11/15/2013 11/15/2013 0 0
Notice the last row. The raw_days value is zero because both valueDate and cutOffDate are the same. If you want that to be one day, add one to the value returned by the DateDiff expression.
After you adjust that preliminary query as needed, you can use it as the data source for another query where you can calculate Age as raw_days - NonWorkDays. But I'll leave that final piece for you in case I've botched the preliminary query.
If subqueries are unfamiliar to you, I recommend two of Allen Browne's pages for useful background information: Subquery basics and Surviving Subqueries.
Also note that correlated subqueries demand extra work from the db engine. That SELECT Count(*) subquery must be run separately for each row of the table. You should have Holidays.holiday indexed to ease the db engine's burden.
It is easy, just read about with clause.
With it, you can run the first query and the second query then take the result and process it in the third query inside with clause
http://www.oracle-base.com/articles/misc/with-clause.php

Group by in t-sql not displaying single result

See the image below. I have a table, tbl_AccountTransaction in which I have 10 rows. The lower most table having columsn AccountTransactionId, AgreementId an so on. Now what i want is to get a single row, that is sum of all amount of the agreement id. Say here I have agreement id =23 but when I ran my query its giving me two rows instead of single column, since there is nano or microsecond difference in between the time of insertion.
So i need a way that will give me row 1550 | 23 | 2011-03-21
Update
I have update my query to this
SELECT Sum(Amount) as Amount,AgreementID, StatementDate
FROM tbl_AccountTranscation
Where TranscationDate is null
GROUP BY AgreementID,Convert(date,StatementDate,101)
but still getting the same error
Msg 8120, Level 16, State 1, Line 1
Column 'tbl_AccountTranscation.StatementDate' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Your group by clause is in error
group by agreementid, convert(date,statementdate,101)
This makes it group by the date (without time) of the statementdate column. Whereas the original is grouping by the statementdate (including time) then for each row of the output, applying the stripping of time information.
To be clear, you weren't supposed to change the SELECT clause
SELECT Sum(Amount) as Amount,AgreementID, Convert(date,StatementDate,101)
FROM tbl_AccountTranscation
Where TranscationDate is null
GROUP BY AgreementID,Convert(date,StatementDate,101)
Because you have a Group By StatementDate.
In your example you have 2 StatementDates:
2011-03-21 14:38:59.470
2011-03-21 14:38:59.487
Change your query in the Group by section instead of StatementDate to be:
Convert(Date, StatementDate, 101)
Have you tried to
Group by (Convert(date,...)
instead of the StatementDate
You are close. You need to combine your two approaches. This should do it:
SELECT Sum(Amount) as Amount,AgreementID, Convert(date,StatementDate,101)
FROM tbl_AccountTranscation
Where TranscationDate is null
GROUP BY AgreementID,Convert(date,StatementDate,101)
If you never need the time, the perhaps you need to change the datatype, so you don't have to do alot of unnecessary converting in most queries. SQL Server 2008 has a date datatype that doesn't include the time. In earlier versions you could add an additional date column that is automatically generated to strip out the time companent so all the dates are like the format of '2011-01-01 00:00:00:000' then you can do date comparisons directly having only had to do the conversion once. This would allow you to have both the actual datetime and just the date.
You should group by DATEPART(..., StatementDate)
Ref: http://msdn.microsoft.com/en-us/library/ms174420.aspx