How to break down smalldatetime into year, month, day indexes? - sql

I am using SQL Server 2008.
I have some dates in my database that I "think" I want to break down into smaller parts. The dates are birthdays and death days. I want to be able to output them like by querying people who were born in October or on May 12th or in 1945.
I was told that a typical way of doing this is to take a date and break it into smaller pieces and put each piece of the date into its own column, like this:
2001-03-12 00:00:00 // EventDate column
Add these columns:
2001 // EventYear column
03 // EventMonth column
12 // EventDay column
First, is this a good way of doing this? If so, second, can I somehow have SQL Server automatically break the date part and put it into its own columns?
I'd appreciate ideas and solutions.

I would recommend that you leave it as a date column and then use DatePart in queries to filter results.
Select * from TABLEX
where DatePart(YEAR,EventDate) = 1945

It doesn't sound like the business requirement is very solidified. For what reason would you need to break out the different parts of the date? If you don't need to, then I wouldn't.
But, if you do find the necessity to do this then I'd utilize computed columns that are persisted. There wil lbe some overhead on an insert, but because there won't be any updates on existing data (your birthdate and death date won't change) then you won't see any performance overhead on a SELECT.
Something like this:
create table DateTest
(
SomeDate datetime not null,
SomeYear as datepart(yy, somedate) persisted,
SomeMonth as datepart(mm, somedate) persisted,
SomeDay as datepart(dd, somedate) persisted
)

Here is what I do.
I have a table "lib.Dates". It has a DATE as primary key.
It has additional columns with additional information to this date. This is for example day of month, day to end of month, week of year etc.
Joining this date table with dates allows me to:
* Get a list of all dates (for example grouping sales per person by date would have no entry for zero sales, this way it can have)
* Do funny things like all dates in week 23 of a year, which is normally harder to get.
This is part of a number of such tables that I have stored procedures maintain daily (-3 years, +5 years).

Related

Displays dates less than the current day's date

In my program, I have a data grid view. I make some amounts due for payment today. I made a display of the amounts that are due and have not been paid (late) I want a code that displays the dates less than the current date of the day I tried that following code but it only fetches the lower days and does not look For the month or year if it is greater or not than the current day's date
tbl = db.readData("SELECT * from Payments where date_batch < CONVERT(varchar(50),GetDate(), 103)", "");
DgvSearch.DataSource = tbl;
The problem with the previous code is that it doesn't fetch the date lower by day, month and year.
Fetches the date less than the current date in terms of day only I want in terms of day, month and year
Ok, so I'm going to assume date_batch is a VARCHAR(10) or similar and contains data like:
28/12/2021
29/11/2021
30/08/2021
31/12/2021
As you can see these "strings that look like dates to a human" are in order. They are not in date order, they are in alphabetical order. Big difference - SQLServer sorts strings alphabetically. When you ask for strings "less than x" it uses alphabetical sorting rules to determine "less than"-ness
Don't stores dates in a string. SQLServer has several date specific datatypes. Use them.
The following process will dig you out of the hole you've dug yourself into:
ALTER TABLE Payments ADD COLUMN BatchDate DATE;
UPDATE Payments SET BatchDate = TRY_CONVERT(Date, date_batch, 103);
Now go look at your table and sanity check it:
SELECT * FROM payments WHERE batchdate is null and date_batch is not null
This shows any dates that didn't convert. Correct their wonky bad data and run the update again.
Do another select, of all the data, and eyeball it; does it look sensible? Do you have any dates that have been put in as 02/03/2021 when they should have been 03/02/2021 etc
Now your table is full of nice dates, get rid of the strings;
ALTER TABLE Payments DROP COLUMN date_batch;
Maybe rename the column, but in SQLServer and c# WeCallThingsNamesLikeThis, we_dont_call_them_names_like_this
sp_rename 'Payments.BatchDate', 'date-batch', 'COLUMN';
Now you can do:
SELECT * FROM payments WHERE batchDate < GetDate()
And never again store dates in a string

Detecting Invalid Dates in Oracle 11g database (ORA-01847 )

I am querying an Oracle 11.2 instance to build a small data mart that includes extracting the date of birth and date of death of people.
Unfortunately the INSERT query (which takes its data from a SELECT) fails due to ORA-01847 (day of month must be between 1 and last day of month).
To find my bad dates I first did:
SELECT extract(day FROM SOME_DT_TM),
extract(month FROM SOME_DT_TM),
COUNT(*)
FROM PERSON
GROUP BY extract(day FROM SOME_DT_TM), extract(month FROM SOME_DT_TM)
ORDER BY COUNT(*) DESC;
It gave me 367 rows, one for each day of the year including NULL and February-29th (leap year). True for the other date column as well, so it looks like the data is fine from a SELECT perspective.
However if I set logging up on my insert
create table registry_new_dates
(some_dob date, some_death_date date);
exec dbms_errlog.create_error_log('SOME_NEW_DATES');
And then run my long insert query:
SELECT some_dob,some_death_date,ora_err_mesg$ FROM ERR$_SOME_NEW_DATES;
I get the following weird results (first 3 rows shown) which makes me think that zip codes have been somehow inserted instead of dates for the 2nd column.
31-DEC-25 35244 "ORA-01847: day of month must be between 1 and last day of month"
13-DEC-33 35244-3402 "ORA-01847: day of month must be between 1 and last day of month"
23-JUN-58 35235 "ORA-01847: day of month must be between 1 and last day of month"
My question is - how do I detect these bad rows (there are 11 apparentlyh) with an SQL statement so I can fix or remove them. Fixing them in the originating table is not an option (no write privileges). I tried using queries like this:
SELECT DECEASED_DT_TM
FROM WH_CLN_PERSON
WHERE DECEASED_DT_TM LIKE '35%'
AND rownum<3;
But it did not find the offending rows.
Not sure if you are still actively researching this (or if you got an answer already).
To find the rows with the bad data, can't you instead select the DOB and the date of death, and express the WHERE clause in terms of DOB - like so:
...WHERE some_dob = to_date('31-DEC-25')
? After you find those rows, you may want to do another query on just one or two of those rows, including a calculated column: dump(date of death). Then post that. We can learn a lot from the dump - the internal representation of the so-called "date" (which may very well be a ZIP code instead). With that in hand we may be able to figure out what's stored, and how to hunt for it.

Comparing Dates in PL/SQL (I'm a beginner, be gentle)

Relatively new to SQL, so still trying to get my head around a couple of concepts.
I have two tables, the first has a bunch of VARCHAR attributes, as well as a 'DAY' column which is in date format, and 'USAGE', a number.
The second table only has one column, 'HOLIDAY_DATE', also datatype date. As the name suggests, this is a bunch of dates corresponding to past and future holidays.
I'm trying to find 'USAGE' on days that are not holidays, by comparing 'DAY' in the first table to 'DATE' in the second. My select statement so far is:
SELECT DAY, USAGE
FROM FIRST_TABLE, HOLIDAYS
WHERE FIRST_TABLE.DAY, NOT LIKE HOLIDAYS.HOLIDAY_DATE
GROUP BY DAY, USAGE
ORDER BY DAY;
But this still seems to bring up ALL the days, including holidays. Not quite sure where to go from here.
SELECT DAY, USAGE
FROM FIRST_TABLE
WHERE FIRST_TABLE.DAY NOT in (select HOLIDAY_DATE from HOLIDAYS)
GROUP BY DAY, USAGE
ORDER BY DAY
there may be other ways but you can use subquery concept
SELECT DAY, USAGE
FROM FIRST_TABLE
WHERE DAY NOT IN(Select HOLIDAY_DATE FROM HOLIDAYS)
GROUP BY DAY, USAGE
ORDER BY DAY;
One More thing I want to add here eventhough your query has logical issue but there is Syntaxt error also
WHERE FIRST_TABLE.DAY, NOT LIKE HOLIDAYS.HOLIDAY_DATE
^

How to extract dates with datatye DATETIME from colum A in table X and put them into Table Y while changing datatype into DATE

Long title, easy meaning:
How is it possible to extract from a date like "2014-04-04 10:47:30.000", which is stored in one column, it's components like year, month and day?
I'm not interested in the time.
For example, I have a table called "Incidents". Inside the table we got a column called "IncidentID" and a column called "ReportingDate", in which dates like the above-mentionend are stored. Let's say we have about 50k Incidents, therefore we have also 50k dates.
A year has 365 days. I want to query for the count of the Incidents, which were reported on different dates - for instance on the 5th of October 2013.
So: How can I get the components of the date and put them into another table while having own columns for the components and how can I query for the Incidents as well?
I guess at first I have to change the datatype of the date from DATETIME to DATE, but I'm not quite sure how to go further. May anyone help me while giving me a code and explains me what it does for a sql-noob? :-)
To achieve this
I want to query for the count of the Incidents, which were reported on
different dates - for instance on the 5th of October 2013.
you haven't do this:
I guess at first I have to change the datatype of the date from
DATETIME to DATE, but I'm not quite sure how to go further.
Just query
SELECT
IncidentID
FROM incidents
WHERE ReportingDate >= '20131005'
AND ReportingDate < '20131006'

PostgreSQL - GROUP BY timestamp values?

I've got a table with purchase orders stored in it. Each row has a timestamp indicating when the order was placed. I'd like to be able to create a report indicating the number of purchases each day, month, or year. I figured I would do a simple SELECT COUNT(xxx) FROM tbl_orders GROUP BY tbl_orders.purchase_time and get the value, but it turns out I can't GROUP BY a timestamp column.
Is there another way to accomplish this? I'd ideally like a flexible solution so I could use whatever timeframe I needed (hourly, monthly, weekly, etc.) Thanks for any suggestions you can give!
This does the trick without the date_trunc function (easier to read).
// 2014
select created_on::DATE from users group by created_on::DATE
// updated September 2018 (thanks to #wegry)
select created_on::DATE as co from users group by co
What we're doing here is casting the original value into a DATE rendering the time data in this value inconsequential.
Grouping by a timestamp column works fine for me here, keeping in mind that even a 1-microsecond difference will prevent two rows from being grouped together.
To group by larger time periods, group by an expression on the timestamp column that returns an appropriately truncated value. date_trunc can be useful here, as can to_char.