Filter dates stored as varchar in SQL Server - sql

I am using SQL Server 2008 R2 on the EC2 instance. I have a database having 4 fields of all varchar(50).
SELECT
*
FROM
xyz
WHERE
DataDate ='20140609'
This query gives no result.
SELECT
*
FROM
xyz
WHERE
DataDate = (Select MAX(DataDate) from xyz)
This query runs perfectly.
Select MAX(DataDate) from xyz
This query results in 20140609.
I cannot understand why this this happening. Can someone please explain this?

As stated in comments it's likely due to leading spaces in the values. If you do the following to remove any spaces from the values it should work:
SELECT *
FROM xyz
WHERE REPLACE(DataDate, ' ', '')='20140609'
Alternately, you could use LTRIM / RTRIM functions to do this.
Sample SQL Fiddle
create table SampleData(myDate varchar(50))
insert into SampleData(myDate) values(' 20140609 ')
insert into SampleData(myDate) values('20140608')
insert into SampleData(myDate) values('20140607')
insert into SampleData(myDate) values('20140606')
Both of these queries work in the fiddle:
SELECT *
FROM SampleData
WHERE REPLACE(myDate, ' ', '')='20140609'
Select MAX(REPLACE(myDate, ' ', '')) from SampleData
Future Advice:
Even so, it's not a good idea to save dates as varchar for numerous reasons so I would suggest changing that if possible.
The below would perform a conversion on your existing data to convert them to valid dates, whilst removing any spaces, assuming your dates are always in the format YYYYMMDD:
SELECT cast(REPLACE(DataDate, ' ', '') as DateTime) FormattedDate
FROM xyz
To implement this, you could create a new DateTime column on the table and insert the correct date values in to there with something like below and then modify your code to use the new column:
First add a new column to the table:
ALTER TABLE xyz
ADD FormattedDate DateTime NULL
Then update the data in the new column so it holds the converted dates:
UPDATE xyz
SET FormattedDate = cast(REPLACE(DataDate, ' ', '') as DateTime)

in sql spaces count as the character. Then use like operator to this query as
SELECT
*
FROM
xyz
WHERE
DataDate like '%20140609%'

Can you modify the query as below and give it a go ?
SELECT
*
FROM
xyz
WHERE
DataDate ='2014-06-09'

Related

How to apply trim function inside this query [duplicate]

Below is simple sql query to select records using in condition.
--like this I have 6000 usernames
select * from tblUsers where Username in ('abc ','xyz ',' pqr ',' mnop ' );
I know there are LTrim & Rtrim in sql to remove the leading trailing spaces form left & right respectively.
I want to remove the spaces from left & right in all the usernames that I am supplying to the select query.
Note:-
I want to trim the values that I am passing in the in clause.(I don't want to pass LTrim & RTrim to each value passed).
There are no trailing space in the records but value that I am passing in the clause is copied from excel & then pasted in Visual Studio. Then using ALT key I put '(single quote) at the left & right sides of the string. Due to this some strings has spaces in the right side trailing.
How to use the trim function in the select query?
I am using MS SQL Server 2012
If I understand your question correctly you are pasting from Excel into an IN clause in an adhoc query as below.
The trailing spaces don't matter. It will still match the string foo without any trailing spaces.
But you need to ensure that there are no leading spaces.
As the source of the data is Excel why not just do it all there?
You can use formula
= CONCATENATE("'",TRIM(SUBSTITUTE(A1,"'","''")),"',")
Then copy the result (from column B in the screenshot above) and just need to trim off the extra comma from the final entry.
You can do like this:
select * from tblUsers where LTRIM(RTRIM(Username)) in (ltrim(rtrim('abc')),ltrim(rtrim('xyz')),ltrim(rtrim('pqr')),ltrim(rtrim('mnop')));
However, if you have permission to update the database. Please remove all the spaces in your Username field. It is really not good to do the query like this.
One way to tackle your problem and still be able to benefit from an index on username is to use a persisted computed column:
Setup
-- drop table dbo.tblUsers
create table dbo.tblUsers
(
UserId INT NOT NULL IDENTITY(1, 1) CONSTRAINT PK_UserTest PRIMARY KEY,
Username NVARCHAR(64) NOT NULL,
UsernameTrimmed AS LTRIM(RTRIM(Username)) PERSISTED
)
GO
-- other columns may be included here with INCLUDE (col1, col2)
CREATE INDEX IDX_UserTest ON dbo.tblUsers (UsernameTrimmed)
GO
insert into dbo.tblUsers (Username) VALUES ('abc '),('xyz '),(' pqr '), (' mnop '), ('abc'), (' useradmin '), ('etc'), (' other user ')
GO
-- some mock data to obtain a large number of records
insert into dbo.tblUsers (Username)
select top 20000 SUBSTRING(text, 1, 64) from sys.messages
GO
Test
-- this will use the index (index seek)
select * from tblUsers where UsernameTrimmed in (LTRIM(RTRIM('abc')), LTRIM(RTRIM(' useradmin ')));
This allows for faster retrievals at the expense of extra space.
In order to get rid of query construction (and the ugliness of many LTRIMs and RTRIMs), you can push searched users in a table that looks like tblUsers.
create table dbo.searchedUsers
(
Username NVARCHAR(64) NOT NULL,
UsernameTrimmed AS LTRIM(RTRIM(Username)) PERSISTED
)
GO
Push raw values into dbo.searchedUsers.Username column and the query should look like this:
select U.*
from tblUsers AS U
join dbo.searchedUsers AS S ON S.UsernameTrimmed = U.UsernameTrimmed
The big picture
It is way better to properly trim your data in the service layer of your application (C#) so that future clients of your table may rely on decent information. So, trimming should be performed both when inserting information into tblUsers and when searching for users (IN values)
select *
from tblUsers
where RTRIM(LTRIM(Username)) in ('abc','xyz','pqr','mnop');
Answer: SELECT * FROM tblUsers WHERE LTRIM(RTRIM(Username)) in ('abc','xyz','pqr','mnop');
However, please note that if you have functions in your WHERE clause it defeats the purpose of having an indexes on that column and will use a
scan than a seek.
I would propose you clean your data before inserting into tblUsers
I think you can try this:
Just replace the table2 with you table name form where you are getting the username
select * from tblUsers where Username in ((select distinct
STUFF((SELECT distinct ', ' + RTRIM(LTRIM(t1.Username))
from table2 t1
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,2,'') UserName
from table2 t) );
I'd do it in two step:
1) populate a temp table with all your strings with blanks
2) do a select with a subselect
create table a (a char(1))
insert into a values('a')
insert into a values('b')
insert into a values('c')
insert into a values('d')
create table #b (atmp char(5))
insert into #b values ('a ')
insert into #b values (' b')
insert into #b values (' c ')
select * from a where a in (select ltrim(rtrim(atmp)) from #b)

Separate value from comma to row SQL Server 2008

Please help me to get value from table like below
Field A has value below
file B
13974
14098
14237
14269
....
and I need to mix values and down value in row like below
13974;14098;14237;14269;14317;14319;14392;14393;13 257;13983;13820
please help me to supports many thanks
For SQL-Server you can use,
select SUBSTRING(
(select ';' + your_column
from your_table
for xml path('')),2,10000) as csv
** 10000 is the end position of the substring. So replace this with the maximum number of characters you expect in your result.
declare #xxx nvarchar(max)
select top 10 #xxx =COALESCE(#xxx+';','')+columnName
from table
select #xxx

How to copy data from one table to another where column data types are different?

I have two tables.
NEW [contains data] [all columns are varchar]
NEW2 [empty table] [columns are of different data types]
I want to copy all data from New to New2.
What i did is,
SELECT T.*
INTO #tmp
FROM (SELECT *
FROM [dbo].[new]) AS T
then
INSERT INTO New2(col1, col2....)
SELECT *
FROM #TMP
But its not working.
Msg 242, Level 16, State 3, Line 2
The conversion of a varchar data type to a smalldatetime data type resulted in an out-of-range value.
The statement has been terminated.
[what I want is to change the column data types of NEW table, especially the varchar to smalldatetime. So I tried this way. Any other approach is also welcome.]
Any help would be greatly appreciated.
Thank You.
Yes. Done.
What I did is,
Imported Excle data in SQL Server table with all columns in a table as varchar data type.
The problem was in excel data, the date values, somewhere was NA. So I had to replace all those NA values with null.
To check for those invalid date values in a table, I used following command.
SELECT ISDATE(COL_NAME) AS Result
SELECT ISNULL(COL_NAME) AS Result
For this, sometime you have to also check & set for the date format of SQL Server using following commands,
DBCC useroptions
SET DATEFORMAT mdy
Then all the result values I replaced them with NULL as
UPDATE TABLE SET COLUMN = NULL WHERE ISDATE(COLUMN) = 0 OR COLUMN = 'NA'
At last I updated required columns manually using simple alter commands as,
ALTER TABLE ALTER COLUMN COL_NAME <<data type>>
I also changed my dateforamat to dmy which prior was mdy.
Thank for Suraj Singh, Deepshikha for their helpful suggestions.
While inserting cast your column to smalldatetime
SET DATEFORMAT ymd
INSERT INTO New2(col1, col2....)
SELECT Col1,Col2 , CAST('2007-05-08 12:35:29' AS smalldatetime) As Col_Name,...Col3
FROM #TMP
Try as:
DECLARE #NEW TABLE([date] VARCHAR(20));
INSERT #NEW SELECT '2/8/2013 15:00' ;
select LEFT([date],2) + SUBSTRING([date],3,2) + SUBSTRING([date],5,4) + ' '+ RIGHT([date],5)+':00'
from #NEW
UPDATE #NEW SET [date] = CONVERT(CHAR(16), CONVERT(SMALLDATETIME,
LEFT([date],2) + SUBSTRING([date],3,2) + SUBSTRING([date],5,4) + ' '+ RIGHT([date],5)+':00', 120));
SELECT [date], CONVERT(SMALLDATETIME, [date]) FROM #NEW;
Try This
SET DATEFORMAT ymd
INSERT INTO destination_table(column_name)
SELECT Column_name As Aliace_name
FROM Source_table

Using cast in insert statement

I am inserting some raw data into a table in MS SQL 2005 from excel.
Some of these data are not formatted correctly ie the amount colum is formatteT as a number 12345 whereas i need to be like 123.45 so i use this
CAST(TRANSACTION_HISTORY.AMOUNT AS decimal) / 100
to convert it correctly.
However is there a way to use the cast in an insert statement??
thanks
You can use CAST in any kind of statement(Insert, update, delete, select) where you use data.
Insert into table1 values( CAST(col1 as nvarchar(50)) )
I assume you're using a linked server or openquery to get the data from excel. You can cast in the select statement.
So
INSERT INTO YourTable
SELECT Cast(Transaction_History.Amount AS Decimal)/100
FROM EXCELLINK...[$Sheet1]
You could also just update all values in the table after you do the import
UPDATE YourTable
SET YourColumn = YourColumn/100

String manipulation SQL

I have a row of strings that are in the following format:
'Order was assigned to lastname,firsname'
I need to cut this string down into just the last and first name but it is always a different name for each record.
The 'Order was assigned to' part is always the same.......
Thanks
I am using SQL Server. It is multiple records with different names in each record.
In your specific case you can use something like:
SELECT SUBSTRING(str, 23) FROM table
However, this is not very scalable, should the format of your strings ever change.
If you are using an Oracle database, you would want to use SUBSTR instead.
Edit:
For databases where the third parameter is not optional, you could use SUBSTRING(str, 23, LEN(str))
Somebody would have to test to see if this is better or worse than subtraction, as in Martin Smith's solution but gives you the same result in the end.
In addition to the SUBSTRING methods, you could also use a REPLACE function. I don't know which would have better performance over millions of rows, although I suspect that it would be the SUBSTRING - especially if you were working with CHAR instead of VARCHAR.
SELECT REPLACE(my_column, 'Order was assigned to ', '')
For SQL Server
WITH testData AS
(
SELECT 'Order was assigned to lastname,firsname' as Col1 UNION ALL
SELECT 'Order was assigned to Bloggs, Jo' as Col1
)
SELECT SUBSTRING(Col1,23,LEN(Col1)-22) AS Name
from testData
Returns
Name
---------------------------------------
lastname,firsname
Bloggs, Jo
on MS SQL Server:
declare #str varchar(100) = 'Order was assigned to lastname,firsname'
declare #strLen1 int = DATALENGTH('Order was assigned to ')
declare #strLen2 int = len(#str)
select #strlen1, #strLen2, substring(#str,#strLen1,#strLen2),
RIGHT(#str, #strlen2-#strlen1)
I would require that a colon or some other delimiter be between the message and the name.
Then you could just search for the index of that character and know that anything after it was the data you need...
Example with format changing over time:
CREATE TABLE #Temp (OrderInfo NVARCHAR(MAX))
INSERT INTO #Temp VALUES ('Order was assigned to :Smith,Mary')
INSERT INTO #Temp VALUES ('Order was assigned to :Holmes,Larry')
INSERT INTO #Temp VALUES ('New Format over time :LootAt,Me')
SELECT SUBSTRING(OrderInfo, CHARINDEX(':',OrderInfo)+1, LEN(OrderInfo))
FROM #Temp
DROP TABLE #Temp