Sorting off of a formatted date - sql

I currently have a table set up which reports history data. I have
SELECT ACTIONTYPE,
BINNUM,
DSID,
LOCATIONNAME,
LOCATIONTYPE,
ORDNO,
ORIGREC,
convert(varchar(10),TIMEOFACTION, 101) +
right(convert(varchar(32),TIMEOFACTION,100),8) as TIMEOFACTION,
TOTALLIFE
FROM DLOCATIONHISTORY
ORDER BY TIMEOFACTION DESC
I have edited the TIMEOFACTION column so that it displays the date-formatted field as mm/dd/yyyy hh:mmAM/PM. However, the program that is referencing my query, is placing AM before PM because A comes before P. What is the best way to resolve my query to prevent this from happening? Is there a different ordering technique I could use?
My current reporting query shows:
**TIMEOFACTION**
12/13/2017 7:29AM
12/12/2017 10:07AM
12/12/2017 9:58AM
12/12/2017 1:51PM
12/12/2017 2:02PM
12/11/2017 11:01AM
When it should show:
**TIMEOFACTION**
12/13/2017 7:29AM
12/12/2017 2:02PM
12/12/2017 1:51PM
12/12/2017 10:07AM
12/12/2017 9:58AM
12/11/2017 11:01AM

LOL, just full reference column with table name or table alias:
SELECT ACTIONTYPE,
BINNUM,
DSID,
LOCATIONNAME,
LOCATIONTYPE,
ORDNO,
ORIGREC,
convert(varchar(10),TIMEOFACTION, 101) +
right(convert(varchar(32),TIMEOFACTION,100),8) as TIMEOFACTION,
TOTALLIFE
FROM DLOCATIONHISTORY
ORDER BY DLOCATIONHISTORY.TIMEOFACTION DESC --<-- here!
Simplified sample
MS SQL Server 2014 Schema Setup:
create table t ( i int, a char(1) );
insert into t values
(1,'a'),
(2,'b'),
(3,'c');
Query 1:
select -1*i as i, a
from t
order by t.i
Results:
| i | a |
|----|---|
| -1 | a |
| -2 | b |
| -3 | c |
Query 2:
select -1*i as i, a
from t
order by i
Results:
| i | a |
|----|---|
| -3 | c |
| -2 | b |
| -1 | a |

You can use a derived table with a column alias, then rename back to the original column name. For example:
DECLARE #table TABLE(TIMEOFACTION datetime)
INSERT INTO #table VALUES
('2017-12-13 07:29:00')
,('2017-12-12 10:07:00')
,('2017-12-12 09:58:00')
,('2017-12-12 13:51:00')
,('2017-12-12 14:02:00')
,('2017-12-11 11:01:00')
SELECT convert(varchar(10),dT.TIMEOFACTION2, 101)
+ right(convert(varchar(32),TIMEOFACTION2,100),8) as TIMEOFACTION
FROM (
SELECT TIMEOFACTION AS TIMEOFACTION2
FROM #table
) AS dT
ORDER BY TIMEOFACTION2 DESC
Produces:
TIMEOFACTION
12/13/2017 7:29AM
12/12/2017 2:02PM
12/12/2017 1:51PM
12/12/2017 10:07AM
12/12/2017 9:58AM
12/11/2017 11:01AM

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);

SQL Sort Numeric Strings After Split

I currently have char values in a table column which are in the format "IS-" and then 1 to 5 numbers, a possible period with either 2 numbers or a letter following the period.
Examples are, IS-1, IS-12, IS-123, IS-123.11, IS-123.a.
I need to split the string so that I grab only the number part, sort the strings ASC, and the bring the strings back together the way they were.
Explanation. I have the following set of values, IS-1170, IS-1171, IS-1172, IS-1173, IS-1174, IS-870.a, IS-871.a, IS-872.a. As you can see, because IS-1 comes before IS-8 they are sorting out of numerical order.
Any idea where to begin? I was thinking of using CASE, but I'm not really sure how to proceed.
Thanks.
Do string functions in your ORDER BY to remove only the number. Something like this should work:
SELECT col
FROM table
ORDER BY CAST(CASE WHEN ISNUMERIC(SUBSTRING(col,4,20)) = 1
THEN SUBSTRING(col,4,20)
ELSE LEFT(SUBSTRING(col,4,20),CHARINDEX('.',SUBSTRING(col,4,20),0)-1)
END AS NUMERIC)
This will first remove the IS- and check if the rest of the string is a number. If it is, it will leave the decimal digits, otherwise it will remove the . and the following alpha characters.
This is assuming your intended ordering in the case of numeric decimal places would be:
IS-123.A
IS-123.1
IS-123.2
If you don't care about what's after the decimal/period, then simply:
ORDER BY CAST(LEFT(SUBSTRING(col,4,20),CHARINDEX('.',SUBSTRING(col,4,20),0)-1) AS NUMERIC)
If I understand you correctly, this might help you:
DECLARE #mockup TABLE(ID INT IDENTITY,YourExample VARCHAR(100));
INSERT INTO #mockup VALUES
('IS-1, IS-12, IS-123, IS-123.11, IS-123.a.')
,('IS-1170, IS-1171, IS-1172, IS-1173, IS-1174, IS-870.a, IS-871.a, IS-872.a');
WITH Splitted AS
(
SELECT *
,CAST('<x>' + REPLACE(m.YourExample,',','</x><x>') + '</x>' AS XML) AS SplitAtComma
FROM #mockup AS m
)
,NumberExtracted AS
(
SELECT s.ID
,part.value('text()[1]','nvarchar(max)') AS OnePart
,CAST('<y>' + REPLACE(REPLACE(part.value('text()[1]','nvarchar(max)'),'.','-'),'-','</y><y>') + '</y>' AS XML).value('/y[2]/text()[1]','int') AS TheNumber
FROM Splitted AS s
CROSS APPLY s.SplitAtComma.nodes('/x') AS A(part)
)
SELECT *
FROM NumberExtracted
ORDER BY ID,TheNumber;
The first CTE uses a string-split via XML to get all values within the original string (btw: never store comma separated values!).
The second CTE will use the same approach to extract the number, typesafe as INT.
You can use this in an ORDER BY finally.
The result:
+----+-----------+-----------+
| ID | OnePart | TheNumber |
+----+-----------+-----------+
| 1 | IS-1 | 1 |
+----+-----------+-----------+
| 1 | IS-12 | 12 |
+----+-----------+-----------+
| 1 | IS-123 | 123 |
+----+-----------+-----------+
| 1 | IS-123.11 | 123 |
+----+-----------+-----------+
| 1 | IS-123.a. | 123 |
+----+-----------+-----------+
| 2 | IS-870.a | 870 |
+----+-----------+-----------+
| 2 | IS-871.a | 871 |
+----+-----------+-----------+
| 2 | IS-872.a | 872 |
+----+-----------+-----------+
| 2 | IS-1170 | 1170 |
+----+-----------+-----------+
| 2 | IS-1171 | 1171 |
+----+-----------+-----------+
| 2 | IS-1172 | 1172 |
+----+-----------+-----------+
| 2 | IS-1173 | 1173 |
+----+-----------+-----------+
| 2 | IS-1174 | 1174 |
+----+-----------+-----------+
IF OBJECT_ID(N'tempdb..##table1', N'U') IS NOT NULL
DROP TABLE ##table1;
create table ##table1(col1 varchar(20))
declare #query as nvarchar(max)
declare #var1 as varchar(max)='IS-1, IS-12, IS-123, IS-123.11, IS-123.a.,IS-1170, IS-1171, IS-1172, IS-1173, IS-1174, IS-870.a, IS-871.a, IS-872.a.'
set #var1=replace(#var1,',','''),(''')
set #var1='('''+#var1+''')'
set #var1=replace(#var1,' ','')
set #query='insert into ##table1 values'+#var1
EXEC sp_executesql #query
IF OBJECT_ID(N'tempdb..##table2', N'U') IS NOT NULL
DROP TABLE ##table2;
select * into ##table2 from ##table1 order by cast(replace(replace(replace(col1,'IS-',''),'.a.',''),'.a','') as float)
declare #results varchar(max)
select #results = coalesce(#results + ', ', '') + convert(varchar(12),col1) from ##table2
select #results
DROP TABLE ##table1
DROP TABLE ##table2

SQL Server Find the date in joining order

I am using MS-SQL Server there are two tables
membership
+---+-----------------+---------------------+----------------
| | membershipName | createddate | price |
+---+-----------------+---------------------+----------------
| 1 | Swimming | 2010-01-01 | 30 |
| 2 | Swimming | 2010-05-01 | 32 |
| 3 | Swimming | 2011-01-01 | 35 |
| 4 | Swimming | 2012-01-01 | 40 |
+---+-----------------+---------------------+----------------
member
+---+-----------------+---------------------+-----------------
| | memberName | membership | joiningDate |
+---+-----------------+---------------------+-----------------
| 0 | Andy | Swimming | 2008-02-02 |
| 1 | John | Swimming | 2010-02-02 |
| 2 | Andy | Swimming | 2011-02-02 |
| 3 | Alice | Swimming | 2015-02-02 |
+---+-----------------+---------------------+----------------
I want find the member's membership price for the right period of time
e.g
Andy return NULL
John return 30
Alice return 40
the best logic is to see
if the joiningDate is in between two start date
if yes choose the earlier date
if not
if the joining date is before the earlier date then use the earliest date
if the joining date is after the latest date then use the latest date
I am a Java programmer, do this in sql is quite tricky for me, any hint would be nice!
edit 1: sorry I forgot to consider month
edit 2: added desirable result
I hope I understood you correctly. try this out:
SELECT TOP 1 ms.Price
FROM membership ms
LEFT JOIN member m
ON m.joiningdate > ms.createdate
WHERE m.id = 3
ORDER BY price DESC
I hope I got this correctly. You might try it like this:
Declared table variable to mock-up a test scenario:
DECLARE #membership TABLE(id INT, membershipName VARCHAR(100),createddate DATETIME,price DECIMAL(10,4));
INSERT INTO #membership VALUES
(1,'Swimming',{d'2010-01-01'},30)
,(2,'Swimming',{d'2010-05-01'},32)
,(3,'Swimming',{d'2011-01-01'},35)
,(4,'Swimming',{d'2012-01-01'},40);
DECLARE #member TABLE(id INT,memberName VARCHAR(100),membership VARCHAR(100),joiningDate DATETIME);
INSERT INTO #member VALUES
(0,'Andy','Swimming',{d'2008-02-02'})
,(1,'John','Swimming',{d'2010-02-02'})
,(2,'Andy','Swimming',{d'2011-02-02'})
,(3,'Alice','Swimming',{d'2015-02-02'});
As you are on SQL-Server 2012 you are lucky. You can use LEAD:
The CTE "Intervalls" will return the membership table as is and it will add one column with one second before the next rows createddate. LEAD helps you to get hands on a value of a later coming row. First I take away one second, then I set a very high date in case of NULL:
WITH Intervalls AS
(
SELECT *
,ISNULL(DATEADD(SECOND ,-1,LEAD(createddate) OVER(ORDER BY createddate)),{d'2100-01-01'}) AS EndOfIntervall
FROM #membership AS ms
)
--The SELECT reads all members and joins them to the membership where their date is in the range according to "Intervalls". Only the case ealier than the first must be treated specially:
SELECT m.*
,ISNULL(i.price, CASE WHEN YEAR(m.joiningDate)<(SELECT MIN(x.createddate) FROM #membership as x)
THEN (SELECT TOP 1 x.price FROM #membership AS x ORDER BY x.createddate ASC) END)
FROM #member AS m
LEFT JOIN Intervalls AS i ON m.joiningDate BETWEEN i.createddate AND i.EndOfIntervall
UPDATE Better approach (thx to Paparis)
SELECT m.*
,ISNULL(Corresponding.price, (SELECT TOP 1 x.price FROM #membership AS x ORDER BY x.createddate ASC)) AS price
FROM #member AS m
OUTER APPLY
(
SELECT TOP 1 ms.price
FROM #membership AS ms
WHERE ms.createddate<=m.joiningDate
ORDER BY ms.createddate DESC
) AS Corresponding
UPDATE 2: Even simpler!
SELECT m.*
,ISNULL
(
(
SELECT TOP 1 ms.price
FROM #membership AS ms
WHERE ms.createddate<=m.joiningDate
ORDER BY ms.createddate DESC
),
(
SELECT TOP 1 x.price FROM #membership AS x ORDER BY x.createddate ASC
)
) AS price
FROM #member AS m

ExactTarget -SFMC SQL Query to Add Days

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 |

Extract characters after a symbol in sql server 2012

I have a table List shown below:
+------+-------------------------------------+
| Code | name |
+------+-------------------------------------+
| A001 | ABBOTT_1000000 |
| A002 | AGCO_1000001 |
| A003 | ALFA LAVAL_1000002 |
| A004 | ALSTOM POWER INDIA LIMITED_1000003 |
| A005 | AMERICAN BUREAU OF SHIPPING_1000004 |
+------+-------------------------------------+
I need to update the table extracting the characters present after _ in name and replace them in code column. like this.
+---------+-------------------------------------+
| Code | name |
+---------+-------------------------------------+
| 1000000 | ABBOTT_1000000 |
| 1000001 | AGCO_1000001 |
| 1000002 | ALFA LAVAL_1000002 |
| 1000003 | ALSTOM POWER INDIA LIMITED_1000003 |
| 1000004 | AMERICAN BUREAU OF SHIPPING_1000004 |
+---------+-------------------------------------+
This is has to be done in sql server 2012. please help me.
Try this
with cte as
(
select substring(name,charindex('_',name)+1,len(name)) as ext_str,*
from yourtable
)
update cte set code = ext_str
You can try to use SUBSTRING in following:
SAMPLE DATA
CREATE TABLE #MyTable
(
Code NVARCHAR(60),
Name NVARCHAR(60)
)
INSERT INTO #MyTable VALUES
('A001','ABBOTT_1000000' ),
('A002','AGCO_1000001' ),
('A003','ALFA LAVAL_1000002' ),
('A004','ALSTOM POWER INDIA LIMITED_1000003' ),
('A005','AMERICAN BUREAU OF SHIPPING_1000004' )
QUERY
UPDATE #MyTable
SET Code = SUBSTRING(Name, CHARINDEX('_', Name) + 1, LEN(Name))
TESTING
SELECT * FROM #MyTable
DROP TABLE #MyTable
OUTPUT
Code Name
1000000 ABBOTT_1000000
1000001 AGCO_1000001
1000002 ALFA LAVAL_1000002
1000003 ALSTOM POWER INDIA LIMITED_1000003
1000004 AMERICAN BUREAU OF SHIPPING_1000004
SQL FIDDLE
DEMO
UPDATE <table>
SET name = STUFF(name, 1, CHARINDEX('_', name), '')
WHERE name like '%[_]%'
You can do this:
First, you select the number that you want to place as code
select substr(name,-1,7) from table_name
After this, you can update the table.So,The complete statement will be :
update table_name t set t.code = (select substr(name,-1,7) from table_name where code = t.code);
You can use RIGHT together with CHARINDEX:
SQL Fiddle
UPDATE tbl
SET Code = RIGHT(Name, LEN(Name) - CHARINDEX('_', Name))
WHERE CHARINDEX('_', Name) > 0