ExactTarget -SFMC SQL Query to Add Days - sql

Running a query to send email subscribers a +X day email. FIRST_PROMO_SUBSCRIBE_DATE is coming from Oracle which they say is not a compatible format from Salesforce SQL so I have;
select * from PROMO_SUBSCRIBERS
where
(ORDER_ENGAGEMENT_LAST_DT > dateadd(day,-335,CAST(FLOOR(CAST(GETDATE() AS FLOAT)) AS DATETIME))
or ORDER_ENGAGEMENT_LAST_DT is null)
and
(ORDER_LAST_DT > dateadd(day,-1,CAST(FLOOR(CAST(GETDATE() AS FLOAT)) AS DATETIME))
or order_last_dt is null)
Are the parentheses correct?

You should just be able to cast the Oracle dates to date. Casting to date will also strip the time portion off of the datetime fields in T-SQL.
SQL Fiddle
MS SQL Server 2008 Schema Setup:
CREATE TABLE promo_subscribers
(
emailaddress varchar(255)
, ORDER_ENGAGEMENT_LAST_DT varchar(15)
, ORDER_LAST_DT varchar(15)
);
INSERT INTO promo_subscribers
(emailaddress, ORDER_ENGAGEMENT_LAST_DT, ORDER_LAST_DT)
VALUES
('test#example.com', '01-APR-98', '01-APR-16'),
('test#example.com', '01-MAY-98', '06-APR-16')
Query 1:
select
emailaddress
, order_engagement_last_dt
, cast(order_engagement_last_dt as date) datecast1
, order_last_dt
, cast(order_last_dt as date) datecast2
, dateadd(day,-335, cast(getDate() as date)) datecast3
, dateadd(day,-1, cast(getDate() as date)) datecast4
from PROMO_SUBSCRIBERS
Results:
| emailaddress | order_engagement_last_dt | datecast1 | order_last_dt | datecast2 | datecast3 | datecast4 |
|------------------|--------------------------|------------|---------------|------------|------------|------------|
| test#example.com | 01-APR-98 | 1998-04-01 | 01-APR-16 | 2016-04-01 | 2015-05-08 | 2016-04-06 |
| test#example.com | 01-MAY-98 | 1998-05-01 | 06-APR-16 | 2016-04-06 | 2015-05-08 | 2016-04-06 |

Related

how to covert 24 hours to 12 hours in existing data

I want to know how my sql like this my problem is every i remove my where clause in my code there have a error (Conversion failed when converting date and/or time from character string.) i remove may where clause because i want to see my all data, the figure below is example only i have so many data
This is the 1st table
| Entries | recordDate | Empid | Reference |
+-----------------------+-------------------------+--------+-----------+
| 0016930507201907:35I | 2019-05-07 00:00:00 000 | 001693 | 1693 |
| 0016930507201917:06O | 2019-05-07 00:00:00 000 | 001693 | 1693 |
| 0016930507201907:35I | 2019-05-08 00:00:00 000 | 001693 | 1693 |
| | 2019-05-08 00:00:00 000 | 001693 | 1693 |
2nd table
| LastName | FirstName | middleName | EmployeeNO |
+----------+-----------+------------+------------+
| Cruz | MA Kimberly | Castillo | 001693 |
this is i want to see
| Name | EmployeeNO | RecordDate | TimeIn | TimeOut |
+-------------------------+------------+-------------------------+--------+---------+
| CRUZ, MA KIMBERLY, CASTILLO | 001693 | 2019-05-07 00:00:00 000 | 07:35am | 05:06pm |
| CRUZ, MA KIMBERLY,CASTILLO | 001693 | 2019-05-08 00:00:00 000 | 07:35am |
this is my code please help me thank you advance for your helping
Select
B.LastName + ',' + B.FirstName + ',' + B.MiddleName[Name] ,
A.[RecordDate],
B.[EmployeeNO],
CONVERT(VARCHAR(08),MIN(IIF(ISNULL(CHARINDEX('I', A.[Entries], 0), 1) > 0, CAST( SUBSTRING(A.[Entries], LEN(A.[Entries]) - 5, 5) AS [TIME]), NULL)), 100) AS [TimeIn],
CONVERT(VARCHAR(08),MAX(IIF(ISNULL(CHARINDEX('O', A.[Entries], 0), 1) > 0,CAST(SUBSTRING(A.[Entries], LEN(A.[Entries]) - 5, 5) AS [TIME]), NULL)),100) AS [TimeOut]
FROM Employees [B]
INNER JOIN [DTR Upload] [A] ON B.EmployeeNo = A.EmpID
GROUP BY B.LastName, B.FirstName, B.MiddleName,B.[EmployeeNO], A.[recordDate]
ORDER BY A.[recordDate] asc, B.LastName +','+B.FirstName + ','+ B.MiddleName ASC
This works for the sample data you have provided. Note however, I assume that recordDate is a varchar, due to it not being a valid datetime value (if it were, 2019-05-07 00:00:00 000 would be 2019-05-07 00:00:00.000; note the . instead of the ). If recordDate isn't a varchar then you won't need need to include the STUFF and CONVERT expressions to "fix" the value in the VALUES operator. Really, however, you should not be storing date(time) data as a varchar; use the appropriate data type for your data (as these values have no time portion other than midnight, date would seem best).
I also return the TimeIn and TimeOut columns as the datatype time. Date and Time datatypes, in SQL Server, don't have a format they are binary values. If you want to display it in a 12 hour format then you need to configure that in your presentation layer, not your SQL:
--Table1 Sample Data
WITH Table1 AS(
SELECT V.Entries,
V.recordDate,
V.Empid,
V.Reference
FROM (VALUES('0016930507201907:35I','2019-05-07 00:00:00 000','001693',1693),
('0016930507201917:06O','2019-05-07 00:00:00 000','001693',1693),
('0016930507201907:35I','2019-05-08 00:00:00 000','001693',1693),
(NULL,'2019-05-08 00:00:00 000','001693',1693)) V(Entries,recordDate,Empid,Reference)),
--Table2 Sample Data
Table2 AS (
SELECT 'Cruz' AS LastName,
'MA Kimberly' AS FirstName,
'Castillo' AS middleName,
'001693' AS EmployeeNO)
--Solution
SELECT STUFF(CONCAT(', ' + T2.LastName, ', ' + T2.FirstName, ', ' + T2.middleName),1,2,'') AS [Name],
T2.EmployeeNO,
T1.recordDate,
MAX(CONVERT(time(0),CASE S.InOut WHEN 'I' THEN SUBSTRING(T1.Entries,15,5) END)) AS TimeIn,
MAX(CONVERT(time(0),CASE S.InOut WHEN 'O' THEN SUBSTRING(T1.Entries,15,5) END)) AS TimeOut
FROM Table1 T1
JOIN Table2 T2 ON T1.Empid = T2.EmployeeNO --These should really have the same name
CROSS APPLY(VALUES(CONVERT(datetime,STUFF(STUFF(T1.recordDate,11,1, 'T'),20,1,'.')),RIGHT(T1.Entries,1))) S(recordDate, InOut)
GROUP BY T2.EmployeeNO,
T1.recordDate,
T2.LastName,
T2.FirstName,
T2.middleName;
Is that what you are after?
;WITH CTE AS
(
SELECT EmployeeNO,
CONCAT(LastName, ',', FirstName, ',', MiddleName) Name,
RecordDate,
CASE WHEN RIGHT(Entries, 1) = 'I'
THEN CAST(REPLACE(RIGHT(Entries, 6), 'I', '') AS TIME)
END TimeIn,
CASE WHEN RIGHT(Entries, 1) = 'O'
THEN CAST(REPLACE(RIGHT(Entries, 6), 'O', '') AS TIME)
END TimeOut
FROM T1 INNER JOIN T2
ON T1.EmpId = T2.EmployeeNO
)
SELECT EmployeeNO,
Name,
RecordDate,
MIN(TimeIn) TimeIn,
MAX(TimeOut) TimeOut
FROM CTE
GROUP BY EmployeeNO,
Name,
RecordDate;
Returns:
+------------+------------------------+-------------------------+----------+----------+
| EmployeeNO | Name | RecordDate | TimeIn | TimeOut |
+------------+------------------------+-------------------------+----------+----------+
| 1693 | Cruz,Kimberly,Castillo | 2019-05-07 00:00:00 000 | 07:35:00 | 17:06:00 |
| 1693 | Cruz,Kimberly,Castillo | 2019-05-08 00:00:00 000 | 07:35:00 | |
+------------+------------------------+-------------------------+----------+----------+
Live Demo
Now, let's talk a bit about the real problems you have.
You are storing dates as string which is bad, always pick the right data type for your data, so you need to store dates as DATE. Also for the Entries has 3 info there, that means a lack of normalization, because it should be 3 column instead.
For example
+----------------+------+---------------------+
| Entries | Kind | EntriesDate |
+----------------+------+---------------------+
| 00169305072019 | 1 | 2019-05-07 07:35:00 |
| 00169305072019 | 0 | 2019-05-07 16:30:00 |
+----------------+------+---------------------+
This way, you won't fall in those issues and things becomes easy.
For the concatenation of the names, if you always needs to get a full name, I suggest that you use a computed column for that, then you don't need to concatenate the names every time
ALTER TABLE <Your Table Name Here>
ADD [FullName] AS CONCAT(LastName, ',', FirstName, ',', MiddleName);

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?

SQL statement to convert dd/mm/yy nvarchar(255) to Date format dd/mm/yyyy

I am struggling with a SQL statement to convert imported data that is in a format dd/mm/yy and of type nvarchar(255) into a date type 'dd/mm/yyyy' format.
The sample data is as follows:
Date:
'23/10/17'
'24/10/17'
'25/10/17'
'26/10/17'
'27/10/17'
To Date Format:
'23/10/2017'
'24/10/2017'
'25/10/2017'
'26/10/2017'
'27/10/2017'
I am using SQL Server 2008 R2
Here you go:
WITH CTE AS (
SELECT '23/10/17' AS MyDate
UNION
SELECT '24/10/17'
UNION
SELECT '25/10/17'
UNION
SELECT '26/10/17'
UNION
SELECT '27/10/17'
)
SELECT * ,
CONVERT(DATE, MyDate,3) AS MyDate,
CONVERT(VARCHAR, CONVERT(DATE, MyDate,3), 103) AS ExactFormat
FROM CTE;
Results:
+----------+---------------------+-------------+
| MyDate | MyDate | ExactFormat |
+----------+---------------------+-------------+
| 23/10/17 | 23.10.2017 00:00:00 | 23/10/2017 |
| 24/10/17 | 24.10.2017 00:00:00 | 24/10/2017 |
| 25/10/17 | 25.10.2017 00:00:00 | 25/10/2017 |
| 26/10/17 | 26.10.2017 00:00:00 | 26/10/2017 |
| 27/10/17 | 27.10.2017 00:00:00 | 27/10/2017 |
+----------+---------------------+-------------+
Demo
Try using CONVERT.
SELECT convert(datetime, datecolumn, 103);
Refer these links for more detail
http://www.sqlusa.com/bestpractices/datetimeconversion/
https://learn.microsoft.com/en-us/sql/t-sql/functions/cast-and-convert-transact-sql
Hope this helps.
USE REPLACE
CONVERT(DATE,REPLACE('23/10/17', '/17', '/2017'))

Discard existing dates that are included in the result, SQL Server

In my database I have a Reservation table and it has three columns Initial Day, Last Day and the House Id.
I want to count the total days and omit those who are repeated, for example:
+-------------+------------+------------+
| | Results | |
+-------------+------------+------------+
| House Id | InitialDay | LastDay |
+-------------+------------+------------+
| 1 | 2017-09-18 | 2017-09-20 |
| 1 | 2017-09-18 | 2017-09-22 |
| 19 | 2017-09-18 | 2017-09-22 |
| 20 | 2017-09-18 | 2017-09-22 |
+-------------+------------+------------+
If you noticed the House Id with the number 1 has two rows, and each row has dates but the first row is in the interval of dates of the second row. In total the number of days should be 5 because the first shouldn't be counted as those days already exist in the second.
The reason why this is happening is that each house has two rooms, and different persons can stay in that house on the same dates.
My question is: how can I omit those cases, and only count the real days the house was occupied?
In your are using SQL Server 2012 or higher you can use LAG() to get the previous final date and adjust the initial date:
with ReservationAdjusted as (
select *,
lag(LastDay) over(partition by HouseID order by InitialDay, LastDay) as PreviousLast
from Reservation
)
select HouseId,
sum(case when PreviousLast>LastDay then 0 -- fully contained in the previous reservation
when PreviousLast>=InitialDay then datediff(day,PreviousLast,LastDay) -- overlap
else datediff(day,InitialDay,LastDay)+1 -- no overlap
end) as Days
from ReservationAdjusted
group by HouseId
The cases are:
The reservation is fully included in the previous reservation: we only need to compare end dates because the previous row is obtained ordering by InitialDay, LastDay, so the previous start date is always minor or equal than the current start date.
The current reservation overlaps with the previous: in this case we adjust the start and don't add 1 (the initial day is already counted), this case include when the previous end is equal to the current start (is a one day overlap).
There is no overlap: we just calculate the difference and add 1 to count also the initial day.
Note that we don't need extra condition for the reservation of a HouseID because by default the LAG() function returns NULL when there isn't a previous row, and comparisons with null always are false.
Sample input and output:
| HouseId | InitialDay | LastDay |
|---------|------------|------------|
| 1 | 2017-09-18 | 2017-09-20 |
| 1 | 2017-09-18 | 2017-09-22 |
| 1 | 2017-09-21 | 2017-09-22 |
| 19 | 2017-09-18 | 2017-09-27 |
| 19 | 2017-09-24 | 2017-09-26 |
| 19 | 2017-09-29 | 2017-09-30 |
| 20 | 2017-09-19 | 2017-09-22 |
| 20 | 2017-09-22 | 2017-09-26 |
| 20 | 2017-09-24 | 2017-09-27 |
| HouseId | Days |
|---------|------|
| 1 | 5 |
| 19 | 12 |
| 20 | 9 |
select house_id,min(initialDay),max(LastDay)
group by houseId
If I understood correctly!
Try out and let me know how it works out for you.
Ted.
While thinking through your question I came across the wonder that is the idea of a Calendar table. You'd use this code to create one, with whatever range of dates your want for your calendar. Code is from http://blog.jontav.com/post/9380766884/calendar-tables-are-incredibly-useful-in-sql
declare #start_dt as date = '1/1/2010';
declare #end_dt as date = '1/1/2020';
declare #dates as table (
date_id date primary key,
date_year smallint,
date_month tinyint,
date_day tinyint,
weekday_id tinyint,
weekday_nm varchar(10),
month_nm varchar(10),
day_of_year smallint,
quarter_id tinyint,
first_day_of_month date,
last_day_of_month date,
start_dts datetime,
end_dts datetime
)
while #start_dt < #end_dt
begin
insert into #dates(
date_id, date_year, date_month, date_day,
weekday_id, weekday_nm, month_nm, day_of_year, quarter_id,
first_day_of_month, last_day_of_month,
start_dts, end_dts
)
values(
#start_dt, year(#start_dt), month(#start_dt), day(#start_dt),
datepart(weekday, #start_dt), datename(weekday, #start_dt), datename(month, #start_dt), datepart(dayofyear, #start_dt), datepart(quarter, #start_dt),
dateadd(day,-(day(#start_dt)-1),#start_dt), dateadd(day,-(day(dateadd(month,1,#start_dt))),dateadd(month,1,#start_dt)),
cast(#start_dt as datetime), dateadd(second,-1,cast(dateadd(day, 1, #start_dt) as datetime))
)
set #start_dt = dateadd(day, 1, #start_dt)
end
select *
into Calendar
from #dates
Once you have a calendar table your query is as simple as:
select distinct t.House_id, c.date_id
from Reservation as r
inner join Calendar as c
on
c.date_id >= r.InitialDay
and c.date_id <= r.LastDay
Which gives you a row for each unique day each room was occupied. If you need a sum of how many days each room was occupied it becomes:
select a.House_id, count(a.House_id) as Days_occupied
from
(select distinct t.House_id, c.date_id
from so_test as t
inner join Calendar as c
on
c.date_id >= t.InitialDay
and c.date_id <= t.LastDay) as a
group by a.House_id
Create a table of all the possible dates and then join it to the Reservations table so that you have a list of all days between InitialDay and LastDay. Like this:
DECLARE #i date
DECLARE #last date
CREATE TABLE #temp (Date date)
SELECT #i = MIN(Date) FROM Reservations
SELECT #last = MAX(Date) FROM Reservations
WHILE #i <= #last
BEGIN
INSERT INTO #temp VALUES(#i)
SET #i = DATEADD(day, 1, #i)
END
SELECT HouseID, COUNT(*) FROM
(
SELECT DISTINCT HouseID, Date FROM Reservation
LEFT JOIN #temp
ON Reservation.InitialDay <= #temp.Date
AND Reservation.LastDay >= #temp.Date
) AS a
GROUP BY HouseID
DROP TABLE #temp

SQL Server 2008 R2 - Select Case When date between dates

I have a table Like this :
---------------------------------------------------------------
| UserID | Amount | PayDate |TransactionType| ...
----------------------------------------------------------------
| 1 | 140 | 2014-09-30 22:00:00.000| 7 |
| 2 | 230 | 2014-09-30 22:00:00.000| 7 |
| 1 | 120 | 2014-08-01 22:00:00.000| 7 |
| 2 | 135 | 2014-07-30 22:00:00.000| 7 |
| 1 | 120 | 2014-09-30 22:00:00.000| 4 |
----------------------------------------------------------------
I wrote the below query but it returns NULL, Please advise on this query as is:
The declared below dates are between 29/09/2014 and 1/10/2014
Declare
#dateStart datetime= CONVERT(VARCHAR(25),DATEADD(dd,-(DAY(GETUTCDATE())+2),GETUTCDATE()),101),
#dateEnd datetime=(CONVERT(VARCHAR(25),DATEADD(dd,-(DAY(GETUTCDATE())-1),GETUTCDATE()),101))
Select
MemberID,
case
when transactionType = 7
and (PayDate between #dateStart and #dateEnd) then Amount
End AS 'Outstanding Amount'
from
MemberPayment
My output should be :
| MemberID | OutStanding Amount|
---------------------------------
| 1 | 140 |
| 2 | 230 |
but the query returns null, what am I doing wrong ? Is the CASE When DATE between DATES used correct in SQL Server 2008 R2 ?
PS: Please note I do not want to change the query to have WHERE Condition.
Thank you in advance stack overflow family.
This should do the work
Declare
#dateStart datetime= DATEADD(dd,-(DAY(GETUTCDATE())+2),GETUTCDATE()),
#dateEnd datetime=DATEADD(dd,-(DAY(GETUTCDATE())-1),GETUTCDATE())
select MemberID, [Outstanding Amount]
from
(
Select
UserID as MemberID,
case
when transactionType = 7
and (PayDate between #dateStart and #dateEnd) then Amount
End AS 'Outstanding Amount'
from
MemberPayment
) As TmpQuery
where [Outstanding Amount] is not null
I removed the convert to varchar from both of your variables.
Then i put a select around your query, to filter just the results with Oustanding Amount not NULL.
Please take note, that I selected UserID as MemberID, because u used UserID in your example.
I tested it with a table, where PayDate is a Datetime Column.
As already mentioned in one of your comments i would prefer the easy method (and it`s much faster!):
Declare
#dateStart datetime= DATEADD(dd,-(DAY(GETUTCDATE())+2),GETUTCDATE()),
#dateEnd datetime=DATEADD(dd,-(DAY(GETUTCDATE())-1),GETUTCDATE())
select UserID, Amount as [Outstanding Amount]
from MemberPayment
where TransactionType = '7'
and PayDate between #dateStart and #dateEnd