Order by numbers desc then by letters asc - sql-server

I have a varchar column and the current order is like this:
select name from table order by name
1value
2value
3value
Avalue
Bvalue
Cvalue
I want to order first by numbers desc and then by letters asc:
3value
2value
1value
Avalue
Bvalue
Cvalue
How can I do this?

You can use TRY_CAST and LEFT to achieve this.
SELECT * FROM
#p
ORDER BY
-- Numeric first
TRY_CAST(LEFT(your_value,1) AS int) DESC,
-- If numeric, sort with a DESC
CASE WHEN
TRY_CAST(LEFT(your_value,1) AS int) IS NOT NULL
THEN
your_value
END DESC,
-- Otherwise, sort with an ASC
CASE WHEN
TRY_CAST(LEFT(your_value,1) AS int) IS NULL
THEN
your_value
END ASC;

Related

Datatype in INNER select statement is defined as MONEY but then is changed in outer SELECT statement to int datatype

In my t-sql code below, in the INNER SELECT I am doing a SUM(t.WrittenPremium) and the t.WrittenPremium is defined as a MONEY datatype but then in the OUTER SELECT statement when I hover over the a.WrittenPremium it is NOW an INT datatype. The reason for the question is that I'm getting an error in a SSRS report that I'm working on from the results of this query stating that the WrittenPremium cannot be converted to String though I'm not trying to convert anything to a string. Any help/direction would be appreciated. Thanks.
Here is my SQL code:
SELECT
CASE
WHEN a.[Period] = '' THEN a.[Year] + ' - Total '+a.TermType
ELSE a.[Year]
END as [Year]
, a.[Period]
, a.TermType
, a.WrittenPremium
FROM (
SELECT
CASE
WHEN GROUPING (t.[Year]) = 1 THEN 'Total'
ELSE t.[Year]
END as [Year]
, ISNULL(t.[Period],'') as [Period]
, ISNULL(t.TermType,'') as TermType
, SUM(t.WrittenPremium) as WrittenPremium
, RN
FROM #temp t
GROUP BY GROUPING SETS ((t.[Year], t.[Period], t.TermType, t.RN), (t.[Year], t.TermType))
) a
ORDER BY 1 asc, a.RN asc, a.TermType;
Under the assuption that Year is an INT datatype I think the type mismatch is happen in the CASE setting Year. Please try this:
CASE
WHEN GROUPING (t.[Year]) = 1 THEN 'Total'
ELSE CAST(t.[Year] AS VARCHAR(10))
END as [Year]

How to remove duplicates where id is on different columns?

I have a problem removing duplicates. What makes duplicates here is I below with an example.
EmployeeID IDnr1 IDnr2
123456 111111 222222
123456 222222 111111
I want to remove one of these lines. Does not matter who.
I have several thousand such duplicate lines.
Thanks in advance
Use a CASE expression in the GROUP BY clause.
Query
select [EmployeeID], min([IDnr1]) [IDnr1], max([IDnr2]) [IDnr2]
from [your_table_name]
group by [EmployeeID],
case when [IDnr1] > [IDnr2] then [IDnr1] else [IDnr2] end,
case when [IDnr1] > [IDnr2] then [IDnr2] else [IDnr1] end;
Find a demo here
One way to do it is use a cte with row_number().
Create and populate sample table (Please save us this step in your future questions)
DECLARE #T AS TABLE
(
EmployeeID int,
IDnr1 int,
IDnr2 int
)
INSERT INTO #T VALUES
(123456, 111111, 222222),
(123456, 222222, 111111),
(123456, 111112, 222222),
(123457, 222222, 111111)
The cte - note the use of case to get the minimum value:
;WITH CTE AS
(
SELECT EmployeeID,
ROW_NUMBER() OVER(PARTITION BY EmployeeID,
CASE WHEN IDnr1 < IDnr2 THEN IDnr1 ELSE IDnr2 END,
CASE WHEN IDnr1 < IDnr2 THEN IDnr2 ELSE IDnr1 END
ORDER BY (SELECT NULL)) rn
FROM #T
)
The delete statement:
DELETE
FROM CTE
WHERE rn > 1
See a live demo on rextester.
However, deleting the duplicates is only a part of the work. You want to make sure no new duplicates can be inserted to the table. To do that, you need to add a check constraint to your table, but first, update the table.
This step will make sure you can add the check constraint:
UPDATE TableName
SET Idnr1 = Idnr2,
Idnr2 = Idnr1
WHERE Idnr1 >= Idnr2
Then, add the check constraint:
ALTER TABLE TableName
ADD CONSTRAINT CK_TableNamePreventDups CHECK(Idnr1 < Idnr2)
GO
This will make sure no new duplicates can be inserted to your table.

TSQL ORDER BY with nulls first or last (at bottom or top)

I have a date column which has some NULL. I want to order by the date column ASC, but I need the NULL s to be at the bottom. How to do it on TSQL?
In standard SQL you can specify where to put nulls:
order by col asc nulls first
order by col asc nulls last
order by col desc nulls first
order by col desc nulls last
but T-SQL doesn't comply with the standard here. The order of NULLs depends on whether you sort ascending or descending in T-SQL:
order by col asc -- implies nulls first
order by col desc -- implies nulls last
With integers you could simply sort by the negatives:
order by -col asc -- sorts by +col desc, implies nulls first
order by -col desc -- sorts by +col asc, implies nulls last
But this is not possible with dates (or strings for that matter), so you must first sort by is null / is not null and only then by your column:
order by case when col is null then 1 else 2 end, col asc|desc -- i.e. nulls first
order by case when col is null then 2 else 1 end, col asc|desc -- i.e. nulls last
Select *
From YourTable
Order By case when DateCol is null then 0 else 1 end
,DateCol
Or even Order By IsNull(DateCol,'2525-12-31')
order by case when col_name is null then 1 else 2 end, col_name asc did the trick on Oracle. However the same on MS SQL Server pushes the NULL records down leaving non null to be on top of the result set.
This did the trick for me just now. Fortunately, I'm working with text. For anything numeric, I'd probably go with all 9's.
COALESCE(c.ScrubbedPath,'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'),
Sometimes, you may need to use a subquery to get this right:
select site_id, site_desc
from (
select null as site_id, 'null' as site_desc
union
select s.site_id,
s.site_code+'--'+s.site_description as site_desc
from site_master s with(nolock)
)x
order by (case when site_id is null then 0 else 1 end), site_desc

How can I ignore duplicate rows where columns do not contain data

I have a table with duplicate rows, however, some of the duplicate rows have columns does not contain data for the same column. How can I remove/ignore only those row where columns are blank? In some instances:
Name Employee# Location City
-----------------------------------------
BowerT 48999 NJ Foods
BowerT 48999 NJ Foods Pearl
BowerT 48999 NJ Foods Johns
BowerT 48999 NJ Foods Johns
I'm using with CTE to delete duplicate, however, if 2nd, 3rd, or 4th row has the data I need for that column, I lose it because these are greater than row 1.
;With hrEmployee as
(
Select
*,
Row_Number () Over (Partition BY Employee_Number order by Employee_Number) As RowNumber
From
[dbo].[hrEmployee]
Where
Employee_Number = '48999'
)
Delete hrEmployees
where RowNumber > 1
What am I missing?
Here is an entire example the relevant code change is:
ROW_NUMBER() OVER (PARTITION BY Employee_Number ORDER BY
CASE WHEN ISNULL(City,'') = '' THEN 1 ELSE 0 END
) as RowNumber
What that does is simply ORDER your results of what you want to keep by saying if the City is null or '' (blank) make it last. You can rank your results anyway you want by specifying different order in your ORDER BY.
DECLARE #Table AS TABLE (Name VARCHAR(10), Employee_Number INT, Location VARCHAR(20), City VARCHAR(20))
INSERT INTO #Table VALUES ('BowerT',48999,'NJ Foods',NULL)
,('BowerT',48999,'NJ Foods','Pearl')
,('BowerT',48999,'NJ Foods','Johns')
,('BowerT',48999,'NJ Foods','Johns')
SELECT *
FROM
#Table
;WITH hrEmployee AS (
SELECT
*
,ROW_NUMBER() OVER (PARTITION BY Employee_Number ORDER BY
CASE WHEN ISNULL(City,'') = '' THEN 1 ELSE 0 END
) as RowNumber
FROM
#Table
where Employee_Number = '48999'
)
DELETE
FROM
hrEmployee
WHERE
RowNumber > 1
SELECT *
FROM
#Table

SQL Case Then: remember and evaluate based on last group result

Example: I have the following case then statement (see here SQL: Order by column, then by substring mix asc and desc ) my warehouse and the locations are in 1 column as follows and the case alternates the rows going from ASC (odd) to DESC (even):
select *
from #temp
order
by substring(id,1,2),
case
when substring(id,1,2)%2=0 then row_number() over (partition by substring(id,1,2) order by SUBSTRING(id,4,3) desc)
else row_number() over (partition by substring(id,1,2) order by SUBSTRING(id,4,3) asc)
end
01-001-A-01
01-002-A-02
01-003-A-03
01-004-A-01
01-005-A-03
02-001-A-01
02-002-A-02
02-003-A-03
02-004-A-01
02-005-A-03
03-001-A-01
03-002-A-02
03-003-A-03
03-004-A-01
03-005-A-03
Now I would like to add the following: I pick an order from row 1 but nothing to pick from row 2 so I want to go to row 3, now I don't want to walk back the aisle to the beginning of row 03-01 because I'm close to 03-05, so I would like that my results should always be alternating between ASC and desc, so after 01-005-A-03 if I have 0 results with 02 then I want 03-005-A-03 meaning that in this case I would like row 3 DESC and row 4 ASC (so always do the opposite than in the previous group?
This is how it should be if no result begins in 02-XXX-X-XX
01-001-A-01
01-002-A-02
01-003-A-03
01-004-A-01
01-005-A-03
03-005-A-01
03-004-A-02
03-003-A-03
03-002-A-01
03-001-A-03
change the ORDER BY clause to
order by
substring(id,1,2),
case
when dense_rank() over (order by substring(id,1,2)) % 2 = 0
then row_number() over (partition by substring(id,1,2) order by SUBSTRING(id,4,3) desc)
else row_number() over (partition by substring(id,1,2) order by SUBSTRING(id,4,3) asc)
end
instead of finding modulo of substring(id,1,2) % 2 , use dense_rank() to get the continuous numbering and then find the modulo of it
Note : the original query would failed if your first segment is not pure numeric

Resources