What is the most efficient way to convert a split-up date to a datetime value in SQL Server 2005? - sql-server-2005

I'm trying to tie together two SQL Server 2005 databases using a view. The source database splits the date across three int fields.
RecordId | RecordYear | RecordMonth | RecordDay
-----------------------------------------------
000001 | 2001 | 1 | 26
000002 | 2002 | 3 | 10
My goal is to create an easier-to-work-with view with a single datetime field for the date, something like below.
RecordId | RecordDate
---------------------
000001 | 2001/01/26
000002 | 2002/03/10
What is the most efficient way to get this done?
Right now, I'm casting each column as a varchar, concatenate them with slash separators, then casting the full varchar as a datetime. I have to feel like there's a more efficient way.
cast(
cast(RecordYear as varchar) + '/' +
cast(RecordMonth as varchar) + '/' +
cast(RecordDay as varchar)
as datetime
) as RecordDate

No, don't cast to string, and definitely not to varchar without length.
Try:
DECLARE #x TABLE
(
RecordId CHAR(6) PRIMARY KEY,
RecordYear INT,
RecordMonth INT,
RecordDay INT
);
INSERT #x VALUES('000001',2001,1,26);
INSERT #x VALUES('000002',2002,3,10);
SELECT
RecordId,
RecordDate = DATEADD(DAY, RecordDay-1,
DATEADD(MONTH, RecordMonth-1,
DATEADD(YEAR, RecordYear-1900, '19000101'
)))
FROM #x
ORDER BY RecordId;
Results:
RecordId RecordDate
-------- ----------
000001 2001-01-26
000002 2002-03-10

Related

Raise Error/ Throw Exception for Certain Condition SQL Server

http://www.sqlfiddle.com/#!18/c913b/1
CREATE TABLE Table1 (
[ID] int PRIMARY KEY,
[Date] date,
[Name] varchar(40)
);
INSERT INTO Table1 (ID, date, Name )
Values ('1','07-20-18','Fred'),
('2','07-15-18','Sam'),
('3','07-20-18','Ben'),
('4','07-19-18','Simon'),
('5','07-25-18','Dave');
Current Query:
DECLARE #StartDate AS DATETIME,
#CurrentDate AS DATETIME
SET #StartDate = GETDATE() -30
SET #CurrentDate = GETDATE()
SELECT [ID], [Date], [Name]
FROM Table1
WHERE [Date] BETWEEN #StartDate AND #CurrentDate
Current result:
| ID | Date | Name |
|----|------------|-------|
| 1 | 2018-07-20 | Fred |
| 2 | 2018-07-15 | Sam |
| 3 | 2018-07-20 | Ben |
| 4 | 2018-07-19 | Simon |
This query compares with the range of day set for the #startdate variable. This can be changed to anything by anyone who wants to run the query. The issue is if someone selects a really large range of dates it crashes. Is there a way i can set an if statement that throws an error message if for example they tried to run a query for longer than 100 days.
Result: ERROR - Please lower the date range
Is this possible at all?

Datetime data type in a CASE expression impacts all other values on SQL Server 2016

I'm attempting to insert a few rows into a table in SQL Server 2016 using the SQL query below. A temp table is used to store the data being inserted, then a loop is used to insert multiple rows into the table.
--Declare temporary table and insert data into it
DECLARE #fruitTransactionData TABLE
(
Category VARCHAR (30),
Species VARCHAR (30),
ArrivalDate DATETIME
)
INSERT INTO #fruitTransactionData ([Category], [Species], [ArrivalDate])
VALUES ('Fruit', 'Apple - Fuji', '2017-06-30')
--Go into loop for each FieldName (there will be 3 rows inserted)
DECLARE #IDColumn INT
SELECT #IDColumn = MIN(ID) FROM FieldNames
WHILE #IDColumn IS NOT NULL
BEGIN
--Insert data into Transactions
INSERT INTO [dbo].[Transactions] ([FieldName], [Result])
SELECT
(SELECT Name FROM FieldNames WHERE ID = #IDColumn),
CASE
WHEN #IDColumn = 1 THEN 1 --Result insert for FieldName 'Category' where ID=1 refers to 'Fruits'
WHEN #IDColumn = 2 THEN 99 --Result insert for FieldName 'Species' where ID=99 refers to 'Apple - Fuji'
WHEN #IDColumn = 3 THEN [data].[ArrivalDate] --Result insert for FieldName 'Date'
ELSE NULL
END
FROM
#fruitTransactionData [data]
--Once a row has been inserted for one FieldName, then move to the next one
SELECT #IDColumn = MIN(ID)
FROM FieldNames
WHERE ID > #IDColumn
END
When inserting the data, the data is inserted, but all the results show dates, when some data weren't meant to be dates.
+-----+------------+---------------------+
| ID | FieldName | Result |
+-----+------------+---------------------+
| 106 | Category | Jan 2 1900 12:00AM |
| 107 | Species | Apr 10 1900 12:00AM |
| 108 | Date | Jun 30 2017 12:00AM |
+-----+------------+---------------------+
If I comment out the row insert of the date, the columns display correctly.
+-----+------------+--------+
| ID | FieldName | Result |
+-----+------------+--------+
| 109 | Category | 1 |
| 110 | Species | 99 |
+-----+------------+--------+
It seems like the insertion of the date converts all the result values to datetime format (eg. Jan 2 1900 12:00 is a conversion of the number 1).
The result I'm trying to get as opposed to the above results is this:
+-----+------------+---------------------+
| ID | FieldName | Result |
+-----+------------+---------------------+
| 106 | Category | 1 |
| 107 | Species | 99 |
| 108 | Date | Jun 30 2017 12:00AM |
+-----+------------+---------------------+
Just for clarification, the Transaction table schema is as follows:
[ID] INT IDENTITY(1, 1) CONSTRAINT [PK_Transaction_ID] PRIMARY KEY,
[FieldName] VARCHAR(MAX) NULL
[Result] VARCHAR(MAX) NULL
SQL Server is making a guess at the data type for the CASE statement. It does this based on its internal precedence order for data types and the following case statement return type rule:
the highest precedence type from the set of types in
result_expressions and the optional else_result_expression.
Since int has a lower precedence order than datetime SQL Server is choosing to use a datetime return type.
Ultimately explicitly normalizing the data types of your case statement to varchar will solve the issue:
CASE WHEN #IDColumn = 1 THEN '1'
WHEN #IDColumn = 2 THEN '99'
WHEN #IDColumn = 3 THEN FORMAT([data].[ArrivalDate]), 'Mon d yyyy h:mmtt')
ELSE NULL
END
In case you are interested SQL Server uses the following precedence order for data types:
user-defined data types (highest)
sql_variant
xml
datetimeoffset
datetime2
datetime
smalldatetime
date
time
float
real
decimal
money
smallmoney
bigint
int
smallint
tinyint
bit
ntext
text
image
timestamp
uniqueidentifier
nvarchar (including nvarchar(max) )
nchar
varchar (including varchar(max) )
char
varbinary (including varbinary(max) )
binary (lowest)
It is converting the format because all types in a CASE should have the same format. I think you want to convert the date as a string (and the numbers too).
SELECT
,(SELECT Name FROM FieldNames WHERE ID=#IDColumn)
,CASE WHEN #IDColumn=1 THEN '1' --Result insert for FieldName 'Category' where ID=1 refers to 'Category Fruits'
WHEN #IDColumn=2 THEN '99' --Result insert for FieldName 'Species' where ID=99 refers to 'Apple - Fuji'
WHEN #IDColumn=3 THEN convert(varchar(MAX), [data].[ArrivalDate], 23) --Result insert for Field Name 'Date'
ELSE null
END
FROM #fruitTransactionData [data]
This is too long for a comment.
What you are trying to do just doesn't make sense. The columns you are inserting into are defined by:
INSERT INTO [dbo].[Transactions]([FieldName], [Result])
---------------------------------^ -----------^
The INSERT is inserting rows with two values, one for "FieldName" and the other for "Result".
So the SELECT portion should return two columns, no more, no fewer. Your SELECT appears to have four. Admittedly, the first two are syntactically incorrect CASE expressions, so the count might be off.
It is totally unclear to me what you want to do, so I can't make a more positive suggestion.

Create work pattern SQL table

I'm looking to create what appears to be quite a simple table in SQL, however, I'm struggling to create it.
The first date at which the work pattern starts is 01/01/1990 (UK date format: dd/mm/yyyy - happy to have this as 1990/01/01 if necessary). The end date of the first period is 8 weeks from the start date (26/02/1990). The start date of the next period is the day after the previous end date (27/02/1990) and so on. I'd want the last end date to be some time in the future (at least 10 years from now).
This is ideally how I want the table to look:
+--------+------------+------------+
| Period | Start Date | End Date |
+--------+------------+------------+
| 1 | 01/01/1990 | 26/02/1990 |
| 2 | 27/02/1990 | 24/04/1990 |
| 3 | 25/04/1990 | 20/06/1990 |
| 4 | 21/06/1990 | 16/08/1990 |
| 5 | 17/08/1990 | 12/10/1990 |
+--------+------------+------------+
Any help much appreciated.
If you are just adding 8 weeks and not considering the weekends you can follow something like this.
DECLARE #tempTable TABLE(
Period INT IDENTITY PRIMARY KEY,
StartDate DateTime,
EndDate DateTime
);
DECLARE #startDate DATETIME = GETDATE();
DECLARE #endDate DATETIME;
DECLARE #currYear INT = DATEPART(YY,#startDate);
DECLARE #endYear INT = #currYear + 10;
WHILE (#currYear <= #endYear)
BEGIN
SET #endDate = DATEADD(WEEK,8,#startDate);
INSERT INTO #tempTable (StartDate, EndDate) VALUES(#startDate, #endDate);
SET #startDate = DATEADD(dd,1,#endDate);
SET #currYear = DATEPART(YY,#startDate);
END;
SELECT Period, FORMAT(StartDate,'dd/MM/yyyy') AS StartDate, FORMAT(EndDate,'dd/MM/yyyy') AS EndDate FROM #tempTable
CREATE TABLE your_table
(
Period INT,
StartDate DATE,
EndDate DATE
)
INSERT INTO your_table
VALUES
(1,'1990-01-01','1990-02-26')
--etc

Oracle: How query where datetime column not null and null values?

I want query datetime column not null and null values.
But i query have not null values now. i want query both values.
Query:
select l.com_code,
l.p_code,
to_char(l.effdate,'dd/mm/yyyy') effdate,to_char(l.expdate,'dd/mm/yyyy') expdate
from RATE_BILL l
where ( to_date('02/06/2016','dd/mm/yyyy') <= to_date(l.effdate,'dd/mm/yyyy')
or to_date('02/06/2016','dd/mm/yyyy') <= to_date(l.expdate,'dd/mm/yyyy') )
Data Sample
com_code | p_code | effdate | expdate
A | TEST01 | 01/01/2016 | 31/05/2016
A | Test01 | 01/06/2016 |
Query Result:
com_code | p_code | effdate | expdate
A | TEST01 | 01/01/2016 | 31/05/2016
A | Test01 | 01/06/2016 |
Column expdate If null = '31/12/9998' but show in DB is null
when query datetime = '02/06/2016' is between should result this
com_code | p_code | effdate | expdate
A | Test01 | 01/06/2016 |
But where query is
where ( to_date('31/05/2016','dd/mm/yyyy') <= to_date(l.effdate,'dd/mm/yyyy') or to_date('31/05/2016','dd/mm/yyyy') <= to_date(l.expdate,'dd/mm/yyyy') )
Result Should
A | TEST01 | 01/01/2016 | 31/05/2016
A | Test01 | 01/06/2016 |
Values Datetime is "Now Datetime"
First of all I must admit that I am not sure to understand the meaning of your text from your wording [no offence intended]. Feel free to comment if this answer does not address your needs.
The where condition of a query is built on the columns of the table/view and their sql data types. There is no need to convert datetime columns to the datetime data type.
Moreover, it is potentially harmful here since it implies an implicit conversion:
date column
-> char /* implicit, default format */
-> date /* express format;
in general will differ from the format the argument
string follows
*/
So change the where condition to:
where to_date('02/06/2016','dd/mm/yyyy') <= l.effdate
or to_date('02/06/2016','dd/mm/yyyy') <= l.expdate
To cater for null values, complement the where condition with 'sufficiently large' datetime to compare against in case of null values in the db columns:
where to_date('02/06/2016','dd/mm/yyyy') <= nvl(l.effdate, to_date('12/31/9998','dd/mm/yyyy'))
or to_date('02/06/2016','dd/mm/yyyy') <= nvl(l.expdate, to_date('12/31/9998','dd/mm/yyyy'))
You are free to use different cutoff dates. For example you might wish to use expdate from rate_bill when it is not null and the current datetime otherwise:
where to_date('02/06/2016','dd/mm/yyyy') <= nvl(l.effdate, to_date('12/31/9998','dd/mm/yyyy'))
or to_date('02/06/2016','dd/mm/yyyy') <= nvl(l.expdate, sysdate)
I don't understand the details of your problem, but I think you have got problems with comparison of null values.
Null values are ignored by comparison. To select these columns, you should explicitly check l.effdate is null
e.g.
-- select with expdate < today or with no expdate
select *
from RATE_BILL l
where l.expdate is null or
l.expdate <= trunc(sysdate)

Complicated daily automatic insert query in 2 tables

I have the following tables with their columns (only the relevant columns are listed):
Entry
EntryID (int/auto-inc)
EmployeeNumber (int)
JustifyDate (datetime)
EntryDate (datetime)
Employee
EmployeeNumber (int)
CoreHourID (int)
WorkingFromHome (bit/bool)
Hour
EntryID (int)
InHour (datetime)
OutHour (datetime)
CoreHour
CoreHourID (int) - not unique
InHour (int)
OutHour (int)
EDIT: I had forgotten to mention that CoreHourID isn't a unique field, table can look like this:
+-----------+-------+-------+----------+
|CoreHourId |InHour |OutHour|Identifier|
+-----------+-------+-------+----------+
| 2 | 9 | 12 | 1 |
| 2 | 14 | 17 | 2 |
| 3 | 7 | 11 | 3 |
| 3 | 15 | 18 | 4 |
+-----------+-------+-------+----------+
Sorry for the big layout, I really don't know how to properly post table information.
Now here's an attempt at explaining what I'm trying to do:
Every day, a row should be inserted in Entry and Hour for all employees who are WorkingFromHome. In the Entry table it should place the corresponding EmployeeNumber, and for JustifyDate it should add whatever day it is when the job is running. For the EntryDate field it should add that day's date, but the time part should be the InHour from the first corresponding CoreHour row.
For the Hour table it should add the EntryID that just got inserted in the Entry table, and the InHour should be the same as the EntryDate and for the OutHour field it should add a DateTime based on the last OutHour corresponding for the employee's CoreHourID.
I'm struggling a lot, so any help is appreciated.
PS: Any comments/questions regarding my explanation are welcome and I will gladly respond.
The following could be encapsulated into a stored procedure that can be executed via a scheduled job. I'm not exactly sure what you meant by for JustifyDate it should add whatever day it is when the job is running.
Declare #NewEntries Table (
EntryId int not null
, EmployeeNumber int not null
, JustifyDate datetime
, EntryDate datetime
)
Insert [Entry]( EmployeeNumber, JustifyDate, EntryDate )
Output Inserted.EntryId, Inserted.EmployeeNumber, Inserted.JustifyDate, Inserted.EntryDate
Into #NewEntries
Select EmployeeNumber
, CURRENT_TIMESTAMP
, DateAdd(hh, CoreHour.InHour, DateAdd(d, 0, CURRENT_TIMESTAMP))
From Employee
Join CoreHour
On CoreHour.CoreHourId = Employee.CoreHourId
Where WorkingFromHome = 1
Insert [Hour]( EntryId, InHour, OutHour )
Select NE.EntryId, DatePart(hh, NE.EntryDate), CoreHour.OutHour
From #NewEntries As NE
Join Employee
On Employee.EmployeeNumber = NE.EmployeeNumber
Join CoreHour
On CoreHour.CoreHourId = Employee.CoreHourId
(Revised to use Output clause).