SQL - Reverse Part of Column - sql

I want to reverse part of column. Ex;
SELECT Column FROM Table ORDER BY Column ASC
Output:
Column
------
Kaan001
Kaan002
Kaan003
Turan001
Turan002
If I use DESC instead of ASC;
Column
------
Turan002
Turan001
Kaan003
Kaan002
Kaan001
But I want this;
Column
------
Turan001
Turan002
Kaan001
Kaan002
Kaan003
Is it possible or not? Please Help me... Thank you..

You can use:
order by left(columnname, len(columnname) - 3) desc,
right(columnname, 3)

You are required to use DESC. It will return the result by the mentioned column in the descending order.
SELECT ColumnName FROM TableName ORDER BY ColumnName DESC
If you are not explicitly mentioned the Column's ORDER BY it will consider as ASC (ascending order) by default.
Demo on db<>fiddle
As per your edited question, the following query will work using PATINDEX
SELECT ColumnName
FROM TableName
ORDER BY LEFT(ColumnName, PATINDEX('%[0-9]%', ColumnName) - 1) DESC,
RIGHT(ColumnName, LEN(ColumnName) - PATINDEX('%[0-9]%', ColumnName) + 1) ASC
Updated db<>fiddle demo

You can try the below query.
create table #temp (
id int identity(1,1),
testCol Varchar(20)
)
insert into #temp values ('Turan002'),('Turan001'),('Kaan003'),('Kaan002'),('Kaan001')
SELECT
* from
#temp order by RTRIM(SUBSTRING( testCol , 1 , CHARINDEX( '0' , testCol) - 1)) desc,
RTRIM(SUBSTRING( testCol , CHARINDEX( '0' , testCol ), LEN( testCol) - (CHARINDEX( '0' , testCol) - 1))) asc
drop table #temp
You can find the demo Here.

From my understanding,
select * from (
values
('Kaan001')
,('Kaan002')
,('Kaan003')
,('Turan001')
,('Turan002')
) d (val)
order by left (val, PATINDEX ('%[0-9]%', val) - 1) desc
, right (val, PATINDEX ('%[0-9]%', val)) -- Here, Patindex returns the first appearance of integer.

Related

SQL Ordering by a substring with a condition

I have data that looks like this:
[Model Number]
[Model Number]*1
[Model Number]*4
[Model Number]*10
[Model Number]*13
And when I select them I would liek to order them by the number after the " * ", I have it almost working but I dont know how to deal with the case where I dont have a " * ". Here is the last part of my query:
ORDER BY
CAST(SUBSTRING(COL_NAME, CHARINDEX('*', COL_NAME) + 1, LEN(COL_NAME)) AS INT) DESC
Thanks for the help
A couple of solutions that should get you what you're after:
ORDER BY TRY_CONVERT(int,RIGHT(COL_NAME, NULLIF(CHARINDEX('*',REVERSE(COL_NAME)),0) -1)) DESC;
ORDER BY TRY_CONVERT(int, STUFF(COL_NAME, 1, NULLIF(CHARINDEX('*', COL_NAME),0),'')) DESC;
The NULLIF resolves the issue if there is no '*', as CHARINDEX will return 0. Then you don't end up passing an invalid (negative) value to the RIGHT function, as NULL - 1 = NULL.
My personal preference would be using STUFF, as REVERSE is quite an expensive function.
You are almost there, try this
declare #t table (col_name varchar(128));
insert into #t (col_name)
values
( '[Model Number]')
, ('[Model Number]*1')
, ('[Model Number]*4')
, ('[Model Number]*10')
, ('[Model Number]*13');
select *
from #t
order by case charindex('*', col_name) when 0 then 0 else cast(substring(col_name, charindex('*', col_name)+1, 10) as int) end desc

How To Check MAX value With a Pattern

For example,
I have output like this :-
ID
---
AB1
AB2
AB3
AB4
BD6
If I use MAX(ID), I will get 'BD6' But I want to check MAX Value For Pattern AB
How can I get that?
Simply filter the Data with ID field and then use Max():
EDIT: If ID contains number with more than 1 digits:
SELECT TOP 1 *
FROM
[Table] AS A
WHERE
RIGHT(ID, LEN(ID) - 2) = (SELECT
MAX(Cast(RIGHT(ID, LEN(ID) - 2) AS Int)) FROM [Table] WHERE ID LIKE 'AB%')
AND
ID LIKE 'AB%'
Try This. It will display all max ID for every String .
select CONCAT(ID,id1) as ID from
(
select left(id, patindex('%[^0-9]%', id) + 1) ID , max(cast(substring(id, PatIndex('%[0-9]%', id),len(id)) as numeric)) id1
from #Table
group by left(id, patindex('%[^0-9]%', id) + 1)
)a
For Specific ID value like 'AB' put value into where clause .
select CONCAT(ID,id1) as ID from
(
select left(id, patindex('%[^0-9]%', id) + 1) ID , max(cast(substring(id, PatIndex('%[0-9]%', id),len(id)) as numeric)) id1
from #Table
group by left(id, patindex('%[^0-9]%', id) + 1)
)a
where ID like '%ab%'
OutPut :
outpur for AB111
Check also live demo here.
Try it,
DECLARE #TABLE TABLE(ID VARCHAR(MAX))
INSERT INTO #TABLE (ID)
VALUES('AB1'),('AB2'),('AB3'),('AB4'),('AB11'),('AB111'),('XY112')
DECLARE #Prefix VARCHAR (10) = 'AB'
SELECT #Prefix + CAST(MAX(CAST(SUBSTRING(ID, (LEN(#Prefix) + 1),
(LEN(ID) - 2)) AS INT)) AS VARCHAR) AS ID FROM #TABLE WHERE ID LIKE
#Prefix +'%'
Try this :
SELECT 'AB' + CONVERT(NVARCHAR(10),MAX(CONVERT(INT, Nums.Numbers)))
FROM (SELECT Substring(ID, 3, 10) as Numbers
FROM #Tab tab
WHERE tab.ID LIKE 'AB%') as Nums
You can see this here => http://rextester.com/MAHKWE99983
Hope this helps!!!
You can get by this query.
create table temp
(
id varchar(10)
);
insert into temp values
('AB111'),
('AB1'),
('AB2'),
('AB3'),
('AB4'),
('BD6'),
('AB111')
;
declare #Pattern varchar(5)
set #Pattern='AB'
select distinct(Id) from temp where Id = #Pattern+convert(varchar(10),(
select MAX(Id) as Maximum from (
SELECT convert(integer,REPLACE( Id,#Pattern,'')) as Id FROM temp
where id like 'AB%'
)as test ))
with tmp as (
select 'AB1' id union all
select 'AB2' id union all
select 'AB3' id union all
select 'AB4' id union all
select 'AB111' id union all
select 'BD6' id
)
select top 1 * from tmp f1
where f1.ID LIKE 'AB%' and cast(SUBSTRING(f1.ID, 3, LEN(ID) -2) as integer) in
(
select max(cast(SUBSTRING(f2.ID, 3, LEN(ID) -2) as integer)) from tmp f2
WHERE f2.ID LIKE 'AB%'
)
SELECT MAX(ID) FROM #Tbl
GROUP BY LEFT(col_name,2)

Split string and take last element

I have a table with this values:
Articles/Search/ArtMID/2681/ArticleID/2218/Diet.aspx
OurStory/MeettheFoodieandtheMD.aspx
TheFood/OurMenu.aspx
I want to get this
Diet.aspx
MeettheFoodieandtheMD.aspx
OurMenu.aspx
How can i do this?
The way to do it in SQL :
SELECT SUBSTRING( string , LEN(string) - CHARINDEX('/',REVERSE(string)) + 2 , LEN(string) ) FROM SAMPLE;
JSFiddle here http://sqlfiddle.com/#!3/41ead/11
SELECT REVERSE(LEFT(REVERSE(columnName), CHARINDEX('/', REVERSE(columnName)) - 1))
FROM tableName
SQLFiddle Demo
ORHER SOURCE(s)
REVERSE
LEFT
CHARINDEX
Please try:
select url,(CASE WHEN CHARINDEX('/', url, 1)=0 THEN url ELSE RIGHT(url, CHARINDEX('/', REVERSE(url)) - 1) END)
from(
select 'Articles/Search/ArtMID/2681/ArticleID/2218/Diet.aspx' as url union
select 'OurStory/MeettheFoodieandtheMD.aspx' as url union
select 'MeettheFoodieandtheMD.aspx' as url
)xx
Try this. It's easier.
SELECT RIGHT(string, CHARINDEX('/', REVERSE(string)) -1) FROM TableName
SELECT REVERSE ((
SELECT TOP 1 value FROM STRING_SPLIT(REVERSE('Articles/Search/ArtMID/2681/ArticleID/2218/Diet.aspx'), '/')
)) AS fName
Result: Diet.aspx
Standard STRING_SPLIT does not allow to take last value.
The trick is to reverse the string (REVERSE) before splitting with STRING_SPLIT, get the first value from the end (TOP 1 value) and then the result needs to be reversed again (REVERSE) to restore the original chars sequence.
Here is the common approach, when working with SQL table:
SELECT REVERSE ((
SELECT TOP 1 VALUE FROM STRING_SPLIT(REVERSE(mySearchString), '/')
)) AS myLastValue
FROM myTable
A slightly more compact way of doing this (similar to ktaria's answer but in SQL Server) would be
SELECT TOP 1 REVERSE(value) FROM STRING_SPLIT(REVERSE(fullPath), '/') AS fileName
The equivalent for PostgreSQL:
SELECT reverse(split_part(reverse(column_name), '/', 1));
Please try the code below:
SELECT SUBSTRING( attachment, LEN(attachment)
- CHARINDEX('/', REVERSE(attachment)) + 2, LEN(attachment) ) AS filename
FROM filestable;
more simple and elegant :
select reverse(SPLIT_PART(reverse('Articles/Search/ArtMID/2681/ArticleID/2218/Diet.aspx'), '/',1))
You can try this too
( SELECT TOP(1) value
FROM STRING_SPLIT(#string, '/')
ORDER BY CHARINDEX('/' + value + '/', '/' + #string+ '-') DESC)
I corrected jazzytomato's solution for single character tokens (D) and for single tokens (Diet.aspx)
SELECT SUBSTRING( string , LEN(string) - CHARINDEX('/','/'+REVERSE(string)) + 2 , LEN(string) ) FROM SAMPLE;
The easiest way in MySQL:
SELECT SUBSTRING_INDEX(string, '/', -1) FROM SAMPLE;
I have more simple solve
SELECT SUBSTRING_INDEX(string, 'SUBSTRING_INDEX(string, '/', -1)', 1) FROM SAMPLE;
reverse(SUBSTRING(reverse(yourString),0,CHARINDEX('/',reverse(yourString)))) as stringLastPart
Create Table #temp
(
ID int identity(1,1) not null,
value varchar(100) not null
)
DECLARE #fileName VARCHAR(100);
INSERT INTO #temp(value) SELECT value from STRING_SPLIT('C:\Users\Documents\Datavalidation\Input.csv','\')
SET #fileName=(SELECT TOP 1 value from #temp ORDER BY ID DESC);
SELECT #fileName AS File_Name;
DROP TABLE #temp

Tricky SQL query requiring search for contains

I have data such as this:
Inventors column in my table
Hundley; Edward; Ana
Isler; Hunsberger
Hunsberger;Hundley
Names are separated by ;. I want to write a SQL query which sums up the count.
Eg. The result should be:
Hundley 2
Isler 1
Hunsberger 2
Edward 1
Ana 1
I could do a group by but this is not a simple group by as you can see. Any ideas/thoughts on how to get this output?
Edit: Changed results so it doesn't create any confusion that a row only contains 2 names.
You can take a look at this. I certainly do not recommend this way if you have lots of data, BUT you can do some modifications and use it and it works like a charm!
This is the new code for supporting unlimited splits:
Declare #Table Table (
Name Nvarchar(50)
);
Insert #Table (
Name
) Select 'Hundley; Edward; Anna'
Union Select 'Isler; Hunsberger'
Union Select 'Hunsberger; Hundley'
Union Select 'Anna'
;
With Result (
Part
, Remained
, [Index]
, Level
) As (
Select Case When CharIndex(';', Name, 1) = 0
Then Name
Else Left(Name, CharIndex(';', Name, 1) - 1)
End
, Right(Name, Len(Name) - CharIndex(';', Name, 1))
, CharIndex(';', Name, 1)
, 1
From #Table
Union All
Select LTrim(
Case When CharIndex(';', Remained, 1) = 0
Then Remained
Else Left(Remained, CharIndex(';', Remained, 1) - 1)
End
)
, Right(Remained, Len(Remained) - CharIndex(';', Remained, 1))
, CharIndex(';', Remained, 1)
, Level
+ 1
From Result
Where [Index] <> 0
) Select Part
, Count(*)
From Result
Group By Part
Cheers
;with cte as
(
select 1 as Item, 1 as Start, CHARINDEX(';',inventors, 1) as Split, Inventors from YourInventorsTable
union all
select cte.Item+1, cte.Split+1, nullif(CHARINDEX(';',inventors, cte.Split+1),0), inventors as Split
from cte
where cte.Split<>0
)
select rTRIM(lTRIM(SUBSTRING(inventors, start,isnull(split,len(inventors)+1)-start))), count(*)
from cte
group by rTRIM(lTRIM(SUBSTRING(inventors, start,isnull(split,len(inventors)+1)-start)))
You can create a split function to split the col values
select splittedValues.items,count(splittedValues) from table1
cross apply dbo.split(col1,';') splittedValues
group by splittedValues.items
DEMO in Sql fiddle
first make one function who take your comma or any other operator(;) separated string into one table and by using that temp table, apply GROUP function on that table.
So you will get count for separate value.
"select d.number,count(*) from (select number from dbo.CommaseparedListToTable('Hundley;Edward;Ana;Isler;Hunsberger;Hunsberger;Hundley',';'))d
group by d.number"
declare #text nvarchar(255) = 'Edward; Hundley; AnaIsler; Hunsberger; Hunsberger; Hundley ';
declare #table table(id int identity,name varchar(50));
while #text like '%;%'
Begin
insert into #table (name)
select SUBSTRING(#text,1,charindex(';',#text)-1)
set #text = SUBSTRING(#text, charindex(';',#text)+1,LEN(#text))
end
insert into #table (name)
select #text
select name , count(name ) counts from #table group by name
Output
name count
AnaIsler 1
Hundley 2
Hunsberger 2
Edward 1

Create a delimitted string from a query in DB2

I am trying to create a delimitted string from the results of a query in DB2 on the iSeries (AS/400). I've done this in T-SQL, but can't find a way to do it here.
Here is my code in T-SQL. I'm looking for an equivelant in DB2.
DECLARE #a VARCHAR(1000)
SELECT #a = COALESCE(#a + ', ' + [Description], [Description])
FROM AP.Checkbooks
SELECT #a
If the descriptions in my table look like this:
Desc 1
Desc 2
Desc 3
Then it will return this:
Desc 1, Desc 2, Desc 3
Essentially you're looking for the equivalent of MySQL's GROUP_CONCAT aggregate function in DB2. According to one thread I found, you can mimic this behaviour by going through the XMLAGG function:
create table t1 (num int, color varchar(10));
insert into t1 values (1,'red'), (1,'black'), (2,'red'), (2,'yellow'), (2,'green');
select num,
substr( xmlserialize( xmlagg( xmltext( concat( ', ', color ) ) ) as varchar( 1024 ) ), 3 )
from t1
group by num;
This would return
1 red,black
2 red,yellow,green
(or should, if I'm reading things correctly)
You can do this using common table expressions (CTEs) and recursion.
with
cte1 as
(select description, row_number() over() as row_nbr from checkbooks),
cte2 (list, cnt, cnt_max) AS
(SELECT VARCHAR('', 32000), 0, count(description) FROM cte1
UNION ALL
SELECT
-- No comma before the first description
case when cte2.list = '' THEN RTRIM(CHAR(cte1.description))
else cte2.list || ', ' || RTRIM(CHAR(cte1.description)) end,
cte2.cnt + 1,
cte2.cnt_max
FROM cte1,cte2
WHERE cte1.row_nbr = cte2.cnt + 1 AND cte2.cnt < cte2.cnt_max ),
cte3 as
(select list from cte2
where cte2.cnt = cte2.cnt_max fetch first 1 row only)
select list from cte3;
I'm trying to do this in OLEDB and from what I understand you can't do this because you can't do anything fancy in SQL for OLEDB like declare variables or create a table. So I guess there is no way.
If you are running DB2 9.7 or higher, you can use LISTAGG function. Have a look here:
http://pic.dhe.ibm.com/infocenter/db2luw/v9r7/index.jsp?topic=%2Fcom.ibm.db2.luw.sql.ref.doc%2Fdoc%2Fr0058709.html