Order By not working on datetime 101 format - sql-server

Create table #temp
(
OrderDate datetime
)
insert into #temp values ('01/21/2015'),('01/20/2014'),('11/12/2013')
select distinct convert(varchar(10),orderdate,101) as OrderDate from #temp
order by convert(varchar(10),orderdate,101) asc
The above query gives me the result like below:
OrderDate
01/20/2014
01/21/2015
11/12/2013
But I want the result like below:
OrderDate
11/12/2013
01/20/2014
01/21/2015
The above is just a sample on which I am trying to do sorting on format 101. In my actual query I need to use distinct keyword and also the columns will come dynamically in the select statement by using parameter.
I can't use group by in my actual query.
Please help.

UPDATE
Referring to your comments the only way I've managed to get the UNIQUE results with only one column orderdate converted to VARCHAR 101 representation while still sorting it according to DATETIME sort order, was using a little workaround with GROUP BY clause:
SELECT
CONVERT(VARCHAR(10), A.OrderDate, 101) as orderdate
FROM
#temp AS A
GROUP BY
CONVERT(VARCHAR(10), A.OrderDate, 101)
ORDER BY
MAX(A.OrderDate) ASC
MAX(A.OrderDate) should always give you the exactly equal value to the value of every group, so it shouldn't be an improper way - I've put a working example with repeats under the following link on SQL Fiddle.
Still maybe the previous two-columned solution would happen to occur helpful:
select distinct
convert(varchar(10),orderdate,101) as OrderDateConverted,
orderdate
from
#temp
order by
orderdate asc
The above query sorts your query results according to DATETIME datatype whereas order by convert(varchar(10),orderdate,101) caused the alphanumeric sort order.

You can use subQuery as follows to solve the issue.
SELECT t.OrderDate FROM (
SELECT distinct Convert(VARCHAR(10), orderdate, 101) AS OrderDate
from #temp ) t
order by cast(t.OrderDate AS DATETIME) asc

Related

SQl Server - Where clause uses maximum date in data

I'm struggling with something i thought would be easy.
I have a table that is updated via an append on most days and has a report date field that shows the date the rows were updated.
I want to join to this table but only pull back the records from the date the table was last updated
Most of the time I could get away just looking for yesterdays date as the table is updated most days
Where [reportdate] > DATEADD(DAY, -1, GETDATE())
But as its not always updated daily, I wanted to rule this issue out. Is there anyway of returning the max date?
I was trying to figure out max (date), but I can't figure out the grouping. I need to return all the fields. The below just seems to return the whole table
SELECT max ([ReportDate]) as reportdate
,[GUID]
,[Make]
,[Model]
,[MPxN]
,[PaymentMode]
,[Consent]
,[Category]
,[Fuel]
,[pkCommCompID]
FROM table
group by guid
,[Make]
,[Model]
,[MPxN]
,[PaymentMode]
,[Consent]
,[Category]
,[Fuel]
,[pkCommCompID]
I could get round it with a temp table that just has the max report date and then using this as the left part of a join
SELECT max ([ReportDate]) as reportdate
FROM [DOMCustomers].[dbo].[DCC_Device_Comms_Compiled]
But The SQL is triggered in Excel so temp tables are problematic (i think).
Is there anyway of returning the max date?
Like this:
SELECT *
FROM SomeTable
where ReportDate = (select max(ReportDate) from SomeTable)
Here is a conceptual example.
It will produce a latest row for each car make.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (ID INT IDENTITY PRIMARY KEY, make VARCHAR(20), ReportDate DATETIME);
INSERT INTO #tbl (make, ReportDate) VALUES
('Ford', '2020-12-31'),
('Ford', '2020-10-17'),
('Tesla', '2020-10-25'),
('Tesla', '2020-12-30');
-- DDL and sample data population, end
;WITH rs AS
(
SELECT *
, ROW_NUMBER() OVER (PARTITION BY make ORDER BY ReportDate DESC) AS seq
FROM #tbl
)
SELECT * FROM rs
WHERE seq = 1;
Seems like a DENSE_RANK and TOP would work (assuming ReportDate is a date):
SELECT TOP (1) WITH TIES
[ReportDate]
,[GUID]
,[Make]
,[Model]
,[MPxN]
,[PaymentMode]
,[Consent]
,[Category]
,[Fuel]
,[pkCommCompID]
FROM YourTable
ORDER BY DENSE_RANK() OVER (ORDER BY ReportDate DESC);
If ReportDate is a date and time value, and you want everything for the latest date (ignoring time), then replace ReportDate with CONVERT(date,ReportDate) in the ORDER BY.

comparing two dates in different AS columns

I have two columns with date values.I'd like to filter them to see the result only when the two columns have similar values.
I have two questions in "Where" part. Can anyone help me with this?
1)How can i compare the value between this two column with date values?
2)If i have varchar value instead of dates, how can i compare two values?
SELECT [USERNAME], count(*) AS [NumberOfHappening], min([date1]) AS [FirstDate], max([date2]) AS [SecondDate]
FROM TableMain
WHERE CAST([FirstDate] AS DATE) = CAST([SecondDate] AS DATE)
GROUP BY [USERNAME]
ORDER BY 'NumberOfHappening' DESC
Thanks.
Are the orginal date values appropriately typed or do you store date/time-values in string columns? If so, you should really change this...
If I get this correctly, you want to find records, where date1 and date2 are on the same day. Casting a DATETIME to DATE will get rid of the time portion.
You can use a CTE to use the column aliases directly
;WITH cte AS
(
SELECT [USERNAME], count(*) AS [NumberOfHappening], min([date1]) AS [FirstDate], max([date2]) AS [SecondDate]
FROM TableMain
GROUP BY [USERNAME]
)
SELECT *
FROM cte
WHERE CAST([FirstDate] AS DATE) = CAST([SecondDate] AS DATE)
ORDER BY NumberOfHappening DESC;

Repeat Customers with multiple purchases on the same day counts a 1

I am trying to wrap my head around this problem. I was asked to create a report that show repeat customers in our database.
One of the requirements is if a customer has more than 1 order on a specific date, it would only count as 1.
Then if they have more than 1 purchase date, they would then count as a repeat customer.
Searching on here, I found this which works for finding the Customers with more then 1 purchase on a specific purchase date.
SELECT DISTINCT s.[CustomerName], s.PurchaseDate
FROM Reports.vw_Repeat s WHERE s.PurchaseDate <> ''
GROUP BY s.[CustomerName] , cast(s.PurchaseDate as date)
HAVING COUNT(*) > 1;
This MSSQL code works like it should, by showing customers who had more than 1 purchase on the same date.
My problem is what would the best approach be to Join this into another query (this is where i need help) that then shows a complete repeat customer list where customers with more than 1 purchase would be returned.
I am using MSSQL. Any help would be greatly appreciated.
You're close, you need to move distinct into your having clause because you want to include only customers that have more than 1 distinct purchase date.
Also, only group by the customer id because the different dates have to be part of the same group for count distinct to work.
SELECT s.[CustomerName], COUNT(distinct cast(s.PurchaseDate as date))
FROM Reports.vw_Repeat s WHERE s.PurchaseDate <> ''
GROUP BY s.[CustomerName]
HAVING COUNT(distinct cast(s.PurchaseDate as date)) > 1;
If you want to pass a parameter to a query and join the result, that's what table-valued functions are for. When you join it, you use CROSS APPLY or OUTER APPLY instead of an INNER JOIN or a LEFT JOIN.
Also, I think this goes without saying, but when you check if PurchaseDate is empty:
WHERE s.PurchaseDate <> ''
Could be issues there... it implies it's a varchar field instead of a datetime (yes?) and doesn't handle null values. You might, at least, want to replace that with ISNULL(s.PurchaseDate, '') <> ''. If it's actually a datetime, use IS NOT NULL instead of <> ''.
(Edited to add sample data and DDL statements. I recommend adding these to SQL posts to assist answerers. Also, I made purchasedate a varchar instead of a datetime because of the string comparison in the query.)
https://technet.microsoft.com/en-us/library/ms191165(v=sql.105).aspx
CREATE TABLE company (company_name VARCHAR(25))
INSERT INTO company VALUES ('Company1'), ('Company2')
CREATE TABLE vw_repeat (customername VARCHAR(25), purchasedate VARCHAR(25), company VARCHAR(25))
INSERT INTO vw_repeat VALUES ('Cust1', '11/16/2017', 'Company1')
INSERT INTO vw_repeat VALUES ('Cust1', '11/16/2017', 'Company1')
INSERT INTO vw_repeat VALUES ('Cust2', '11/16/2017', 'Company2')
CREATE FUNCTION [dbo].tf_customers
(
#company varchar(25)
)
RETURNS TABLE AS RETURN
(
SELECT s.[CustomerName], cast(s.PurchaseDate as date) PurchaseDate
FROM vw_Repeat s
WHERE s.PurchaseDate <> '' AND s.Company = #company
GROUP BY s.[CustomerName] , cast(s.PurchaseDate as date)
HAVING COUNT(*) > 1
)
GO
SELECT *
FROM company c
CROSS APPLY tf_customers(c.company_name)
First thanks to everyone for the help.
#MaxSzczurek suggested I use table-valued functions. After looking into this more, I ended up using just a temporary table first to get the DISTINCT purchase dates for each Customer. I then loaded that into another temp table RIGHT JOINED to the main table. This gave me the result I was looking for. Its a little(lot) ugly, but it works.

Identify ranges in groups which are identified by a flag

I have the following table:
declare #table table (dates int , is_missing tinyint, group_id numeric(18))
insert into #table(dates,is_missing,group_id)
select 20110719,0,1
union all
select 20110720,0,1
union all
select 20110721,0,1
union all
select 20110722,1,1
union all
select 20110723,0,1
union all
select 20110724,0,1
union all
select 20110725,0,1
union all
select 20110726,1,1
union all
select 20110727,0,1
union all
select 20110728,1,1
union all
select 20110723,1,3
union all
select 20110724,0,3
union all
select 20110725,0,3
union all
select 20110726,1,3
union all
select 20110727,0,3
select * from #table
order by group_id, dates
What I am trying to do is to return ranges of dates for each group which are identified by the missing day flag. To make this more clear the results of the query will have to look like this:
group_id start_date end_date days_count
1 20110719 20110721 3
1 20110723 20110725 3
1 20110727 20110727 1
3 20110724 20110725 2
3 20110727 20110727 1
The is_missing flag basicaly separates the ranges per group. It actually says that a date is missing and therefore all the other dates located between is_missing flags are the groups I am trying to find their start and end dates as well as their days numbers count.
Is there a simple way to do this?
Thanks a lot.
Here is a possible solution using Common Table Expression (CTE) and ROW_NUMBER(). This type of problem is known as islands. Using the concept that was used in this Stack Overflow question: sql group by only rows which are in sequence, the following query was formulated to produce desired output against the data provided by you.
This query works correctly if the data stored in the table is ordered by group_id and dates columns. I assume that is the case with your data. If not, you might need to tweak the solution.
Modified the query as per suggestions provided by Andriy M. Thanks to Andriy M.
The query has been changed so that it can provide correct output even if the date values in the table are not in sequence. The question has the date values stored in int data type instead of date format. So, two queries have been provided below. First query will work if the table contains date values stored in int data typeand the second query will work if the table contains date values stored in datetime or date data type.
This query will work only in SQL Server versions 2005 and above. Since you have tagged your question under sql-server-2008, I think this should work for you.
Screenshot #1 displays the data stored in the table. Screenshot #2 displays the output of the below mentioned queries against the table data.
Hope that helps.
Query for date values stored in int data type:
.
WITH cte AS
(
SELECT datenumeric
, is_missing
, group_id
, datenumeric
- DENSE_RANK() OVER (PARTITION BY is_missing ORDER BY group_id, datenumeric) AS partition_grp
FROM dbo.table_data
)
SELECT cte.group_id
, MIN(cte.datenumeric) AS start_date
, MAX(cte.datenumeric) AS end_date
, COUNT(cte.datenumeric) AS days_count
FROM cte
WHERE cte.is_missing = 0
GROUP BY cte.group_id
, cte.partition_grp
ORDER BY cte.group_id
, cte.partition_grp;
Query for date values stored in datetime or date data type:
.
WITH cte AS
(
SELECT datevalue
, is_missing
, group_id
, DATEDIFF(DAY, 0, datevalue)
- DENSE_RANK() OVER (PARTITION BY is_missing ORDER BY group_id, datevalue) AS partition_grp
FROM dbo.table_data
)
SELECT cte.group_id
, MIN(cte.datevalue) AS start_date
, MAX(cte.datevalue) AS end_date
, COUNT(cte.datevalue) AS days_count
FROM cte
WHERE cte.is_missing = 0
GROUP BY cte.group_id
, cte.partition_grp
ORDER BY cte.group_id
, cte.partition_grp;
Screenshot #1:
Screenshot #2:
With many thanks to Siva for the nice solution, I thought if there was one date missing in the data, the query would fail.
so I modified the query a little and used ROW_NUMBER() to fix that.
WITH cte AS
(
SELECT dates
, is_missing
, group_id
,ROW_NUMBER() OVER (ORDER BY group_id, dates) -
DENSE_RANK() OVER (PARTITION BY is_missing ORDER BY group_id, dates) AS partition_Id
FROM dbo.table_data
)
SELECT group_id
, MIN(dates) AS start_date
, MAX(dates) AS end_date
, COUNT(*) AS days_count
FROM cte
WHERE is_missing = 0
GROUP BY group_id
, partition_id
ORDER BY group_id
, partition_id;
Or maybe a missing date will never happen. :)

Generate Row Serial Numbers in SQL Query

I have a customer transaction table. I need to create a query that includes a serial number pseudo column. The serial number should be automatically reset and start over from 1 upon change in customer ID.
Now, I am familiar with the row_number() function in SQL. This doesnt exactly solve my problem because to the best of my knowledge the serial number will not be reset in case the order of the rows change.
I want to do this in a single query (SQL Server) and without having to go through any temporary table usage etc. How can this be done?
Sometime we might don't want to apply ordering on our result set to add serial number. But if we are going to use ROW_NUMBER() then we have to have a ORDER BY clause. So, for that we can simply apply a tricks to avoid any ordering on the result set.
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS ItemNo, ItemName FROM ItemMastetr
For that we don't need to apply order by on our result set. We'll just add ItemNo on our given result set.
select
ROW_NUMBER() Over (Order by CustomerID) As [S.N.],
CustomerID ,
CustomerName,
Address,
City,
State,
ZipCode
from Customers;
I'm not certain, based on your question if you want numbered rows that will remember their numbers even if the underlying data changes (and gives a different ordering), but if you just want numbered rows - that reset on a change in customer ID, then try using the Partition by clause of row_number()
row_number() over(partition by CustomerID order by CustomerID)
Implementing Serial Numbers Without Ordering Any of the Columns
Demo SQL Script-
IF OBJECT_ID('Tempdb..#TestTable') IS NOT NULL
DROP TABLE #TestTable;
CREATE TABLE #TestTable (Names VARCHAR(75), Random_No INT);
INSERT INTO #TestTable (Names,Random_No) VALUES
('Animal', 363)
,('Bat', 847)
,('Cat', 655)
,('Duet', 356)
,('Eagle', 136)
,('Frog', 784)
,('Ginger', 690);
SELECT * FROM #TestTable;
There are ‘N’ methods for implementing Serial Numbers in SQL Server. Hereby, We have mentioned the Simple Row_Number Function to generate Serial Numbers.
ROW_NUMBER() Function is one of the Window Functions that numbers all rows sequentially (for example 1, 2, 3, …) It is a temporary value that will be calculated when the query is run. It must have an OVER Clause with ORDER BY. So, we cannot able to omit Order By Clause Simply. But we can use like below-
SQL Script
IF OBJECT_ID('Tempdb..#TestTable') IS NOT NULL
DROP TABLE #TestTable;
CREATE TABLE #TestTable (Names VARCHAR(75), Random_No INT);
INSERT INTO #TestTable (Names,Random_No) VALUES
('Animal', 363)
,('Bat', 847)
,('Cat', 655)
,('Duet', 356)
,('Eagle', 136)
,('Frog', 784)
,('Ginger', 690);
SELECT Names,Random_No,ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS SERIAL_NO FROM #TestTable;
In the Above Query, We can Also Use SELECT 1, SELECT ‘ABC’, SELECT ” Instead of SELECT NULL. The result would be Same.
SELECT ROW_NUMBER() OVER (ORDER BY ColumnName1) As SrNo, ColumnName1, ColumnName2 FROM TableName
select ROW_NUMBER() over (order by pk_field ) as srno
from TableName
Using Common Table Expression (CTE)
WITH CTE AS(
SELECT ROW_NUMBER() OVER(ORDER BY CustomerId) AS RowNumber,
Customers.*
FROM Customers
)
SELECT * FROM CTE
I found one solution for MYSQL its easy to add new column for SrNo or kind of tepropery auto increment column by following this query:
SELECT #ab:=#ab+1 as SrNo, tablename.* FROM tablename, (SELECT #ab:= 0)
AS ab
ALTER function dbo.FN_ReturnNumberRows(#Start int, #End int) returns #Numbers table (Number int) as
begin
insert into #Numbers
select n = ROW_NUMBER() OVER (ORDER BY n)+#Start-1 from (
select top (#End-#Start+1) 1 as n from information_schema.columns as A
cross join information_schema.columns as B
cross join information_schema.columns as C
cross join information_schema.columns as D
cross join information_schema.columns as E) X
return
end
GO
select * from dbo.FN_ReturnNumberRows(10,9999)

Resources