MS SQL - How to order results by wildcard? - sql

Query:
SELECT [Name]
FROM [dbo].[City]
where name like '%laus%'
Results:
How to order so records with leading wildcard (3,4) are first?

Your may try, but best way use full-text-search
SELECT [Name]
FROM [City]
where name like '%laus%'
ORDER BY
CHARINDEX('laus',name)

Try This
;WITH CTE(name )
AS
(
SELECT 'Berlin' UNION ALL
SELECT 'Laura' UNION ALL
SELECT 'Losangels' UNION ALL
SELECT 'Lausanne' UNION ALL
SELECT 'Lausen' UNION ALL
SELECT 'Roamanel' UNION ALL
SELECT 'Sankt Niklaus' UNION ALL
SELECT 'Vennes sur-Lausanne'
)
SELECT * FROM CTE
ORDER BY (CASE WHEN name like 'Laus%' THEN 1 END ) DESC
Result
name
--------
Lausanne
Lausen
Losangels
Laura
Roamanel
Sankt Niklaus
Vennes sur-Lausanne
Berlin

DECLARE #City TABLE(Name VARCHAR(32))
INSERT #City VALUES
('Belmont-sur-Lausanne'),
('Lausanne'),
('Lausen'),
('Le Mont-sur-Lausanne'),
('Berlin')
SELECT [Name]
FROM #City
--where name like '%laus%'
order by CASE WHEN PATINDEX('%laus%', name) = 0
THEN LEN(name)
ELSE PATINDEX('%laus%', name)
END
,name

Related

Increment a Counter within a SQL SELECT Case Statement Query

I have some sample data that gives the following results:
**Name**
NULL
Bob
Steven
Jane
Susan
What should happen is the query should convert the NULLs and empty strings to a value of Anom[Counter], so it would end up like this:
**Name**
Anom1
Bob
Steven
Jane
Anom2
Susan
The basic query I have is the below, but how can I auto-increment the number?
select
CASE WHEN Name is NULL or Name = '' THEN 'Anom1' Else Name END
from
Names
Sample data
Create Table Names
(
Name varchar(50) NULL
)
insert into Names
(
Name
)
select
NULL
union all
select
'Bob'
union all
select
'Steven'
union all
select
'Jane'
union all
select
''
union all
select
'Susan'
use row_number() to generate the running number and concat to concatenate it with the string Anom
SELECT CASE WHEN [Name] IS NULL
OR [Name] = ''
THEN CONCAT('Anom', ROW_NUMBER() OVER (PARTITION BY NULLIF([Name], '')
ORDER BY [Name]))
ELSE [Name]
END
FROM [Names]
You can achieve this with a row_number like so
select IsNull(NullIf(Name,''),Concat('Anon', Row_Number() over(partition by IsNull(NullIf(Name,''),'Anon') order by Name) ) ) Names
from names
order by [name]

distinct and sum if like

I have a table as the following
name
-----------
1#apple#1
2#apple#2
3#apple#4
4#box#4
5#box#5
and I want to get the result as:
name
--------------
apple 3
box 2
Thanks in advance for your help
This is what you need.
select
SUBSTRING(
name,
CHARINDEX('#', name) + 1,
LEN(name) - (
CHARINDEX('#', REVERSE(name)) + CHARINDEX('#', name)
)
),
count(1)
from
tbl
group by
SUBSTRING(
name,
CHARINDEX('#', name) + 1,
LEN(name) - (
CHARINDEX('#', REVERSE(name)) + CHARINDEX('#', name)
)
)
If your data does not contain any full stops (or periods depending on your vernacular), and the length of your string is less than 128 characters, then you can use PARSENAME to effectively split your string into parts, and extract the 2nd part:
DECLARE #T TABLE (Val VARCHAR(20));
INSERT #T (Val)
VALUES ('1#apple#1'), ('2#apple#2'), ('3#apple#4'),
('4#box#4'), ('5#box#5');
SELECT Val = PARSENAME(REPLACE(t.Val, '#', '.'), 2),
[Count] = COUNT(*)
FROM #T AS t
GROUP BY PARSENAME(REPLACE(t.Val, '#', '.'), 2);
Otherwise you will need to use CHARINDEX to find the first and last occurrence of # within your string (REVERSE is also needed to get the last position), then use SUBSTRING to extract the text between these positions:
DECLARE #T TABLE (Val VARCHAR(20));
INSERT #T (Val)
VALUES ('1#apple#1'), ('2#apple#2'), ('3#apple#4'),
('4#box#4'), ('5#box#5');
SELECT Val = SUBSTRING(t.Val, x.FirstPosition + 1, x.LastPosition - x.FirstPosition),
[Count] = COUNT(*)
FROM #T AS t
CROSS APPLY
( SELECT CHARINDEX('#', t.Val) ,
LEN(t.Val) - CHARINDEX('#', REVERSE(t.Val))
) AS x (FirstPosition, LastPosition)
GROUP BY SUBSTRING(t.Val, x.FirstPosition + 1, x.LastPosition - x.FirstPosition);
use case when
select case when name like '%apple%' then 'apple'
when name like '%box%' then 'box' end item_name,
count(*)
group by cas when name like '%apple%' then 'apple'
when name like '%box%' then 'box' end
No DBMS specified, so here is a postgres variant. The query does use regexps to simplify things a bit.
with t0 as (
select '1#apple#1' as value
union all select '2#apple#2'
union all select '3#apple#4'
union all select '4#box#4'
union all select '5#box#5'
),
trimmed as (
select regexp_replace(value,'[0-9]*#(.+?)#[0-9]*','\1') as name
from t0
)
select name, count(*)
from trimmed
group by name
order by name
DB Fiddle
Update
For Oracle DMBS, the query stays basically the same:
with t0 as (
select '1#apple#1' as value from dual
union all select '2#apple#2' from dual
union all select '3#apple#4' from dual
union all select '4#box#4' from dual
union all select '5#box#5' from dual
),
trimmed as (
select regexp_replace(value,'[0-9]*#(.+?)#[0-9]*','\1') as name
from t0
)
select name, count(*)
from trimmed
group by name
order by name
NAME | COUNT(*)
:---- | -------:
apple | 3
box | 2
db<>fiddle here
Update
MySQL 8.0
with t0 as (
select '1#apple#1' as value
union all select '2#apple#2'
union all select '3#apple#4'
union all select '4#box#4'
union all select '5#box#5'
),
trimmed as (
select regexp_replace(value,'[0-9]*#(.+?)#[0-9]*','$1') as name
from t0
)
select name, count(*)
from trimmed
group by name
order by name
name | count(*)
:---- | -------:
apple | 3
box | 2
db<>fiddle here
You can use case and group by to do the same.
select new_col , count(new_col)
from
(
select case when col_name like '%apple%' then 'apple'
when col_name like '%box%' then 'box'
else 'others' end new_col
from table_name
)
group by new_col
;

Concatenate results in select

I am trying to insert values into a table that come from an other (lookup) table.
The first 3 results from the table are selected and need to be concatenated before they are inserted into an other table.
How can I alter the following insert to first concatenates them with no separation characters between the 3 names (example: JohnMaxLouise)?
INSERT INTO Table 2 VALUES ((SELECT TOP 3 names FROM Table1 ORDER BY NEWID()))
I am using SQL Server 2016 so string_agg is not available.
Personally, I think this is simplest with conditional aggregation:
INSERT INTO Table2
SELECT (MAX(CASE WHEN seqnum = 1 THEN name ELSE '' END) +
MAX(CASE WHEN seqnum = 2 THEN name ELSE '' END) +
MAX(CASE WHEN seqnum = 3 THEN name ELSE '' END)
)
FROM (SELECT name, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) as seqnum
FROM (SELECT TOP 3 name
FROM Table1
ORDER BY NEWID()
) t
) t;
An alternative is an XML approach, but if you know you want three, then conditional aggregation (or pivot) works fine.
try the following:
declare #tab table (names varchar(max))
declare #tab1 table ([name] varchar(100))
insert into #tab1
select 'John' union select 'Max' union select 'Louise' union select 'xxx'
insert into #tab select (select top 3 [name] + '' from #tab1 for xml path(''))
select * from #tab
Thanks.
This will return '1,2,3,4'
DECLARE #x TABLE (i INTEGER)
DECLARE #r VARCHAR(255)
INSERT INTO #x VALUES (1),(3),(2),(4)
SELECT #r= STUFF(( SELECT ',' + CAST(i AS VARCHAR(max))
FROM #x
ORDER BY i
FOR XML PATH(''), type
).value('.','varchar(255)'), 1, 1, '')
SELECT #r
Solution Overview
You can use FOR XML PATH('') to achieve this, just use the following command:
SELECT '' + NAME
FROM (SELECT Top 3 NAME FROM TBL_1 ORDER BY NEWID()) AS T
FOR XML PATH('')
Or simple concatenation
SELECT #x = #x + NAME
FROM (SELECT Top 3 NAME FROM TBL_1 ORDER BY NEWID()) AS T1
Detailed Solution
SQLFiddle Demo
First i created the test environment using the following query
CREATE TABLE TBL_1 (NAME Varchar(50))
CREATE TABLE TBL_2 (NAME Varchar(50))
INSERT INTO TBL_1 (Name) VALUES ('John'),('Max'),('Louise'),('Mark'),('Peter')
Then i Used the following command
DECLARE #x varchar(255)
SELECT #x = (SELECT '' + NAME
FROM (SELECT Top 3 NAME FROM TBL_1 ORDER BY NEWID()) AS T1
FOR XML PATH('') )
INSERT INTO TBL_2(NAME) SELECT #x;
SELECT * FROM TBL_2
And the Result is JohnLouiseMax
Or you can use simple concatenation to achieve this
SQLFiddle Demo
DECLARE #x varchar(255)
SET #x = ''
SELECT #x = #x + NAME
FROM (SELECT Top 3 NAME FROM TBL_1 ORDER BY NEWID()) AS T1
INSERT INTO TBL_2(NAME) SELECT #x;
SELECT * FROM TBL_2

Print result by merging records in a table

I have a table with name "PrintWord" and column name as col_letter and data in it is as follows:
"col_letter"
S
A
C
H
I
N
I would like to print the o/p from this table as:
SACHIN
Thanks!
DECLARE #t table
(
Name varchar(10)
)
INSERT INTO #t
SELECT 's' UNION ALL
SELECT 'a' UNION ALL
SELECT 'c' UNION ALL
SELECT 'h' UNION ALL
SELECT 'i' UNION ALL
SELECT 'n'
SELECT DISTINCT
stuff(
(
SELECT ' '+ [Name] FROM #t FOR XML PATH('')
),1,1,'')
FROM (SELECT DISTINCT Name FROM #t ) t
There is a hard-coded version :
SELECT col_letter
FROM PrintWord
ORDER BY
CASE col_letter
WHEN 'S' THEN 1
WHEN 'A' THEN 2
WHEN 'C' THEN 3
WHEN 'H' THEN 4
WHEN 'I' THEN 5
WHEN 'N' THEN 6
END
FOR XML PATH('')
You need an ORDER BY clause to guarantee the order of the letters.

SQL query problem

Let´s say I have two tables, "Garden" and "Flowers". There is a 1:n-relationship between these tables, because in a garden can be many flowers. Is it possible to write an SQL query which returns a result with the following structure:
GardenName Flower1Name Flower2Name .... (as long as there are entries in flowers)
myGarden rose tulip
CREATE TABLE #Garden (Id INT, Name VARCHAR(20))
INSERT INTO #Garden
SELECT 1, 'myGarden' UNION ALL
SELECT 2, 'yourGarden'
CREATE TABLE #Flowers (GardenId INT, Flower VARCHAR(20))
INSERT INTO #Flowers
SELECT 1, 'rose' UNION ALL
SELECT 1, 'tulip' UNION ALL
SELECT 2, 'thistle'
DECLARE #ColList nvarchar(max)
SELECT #ColList = ISNULL(#ColList + ',','') + QUOTENAME('Flower' + CAST(ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS VARCHAR))
FROM #Flowers WHERE GardenId = (
SELECT TOP 1 GardenId
FROM #Flowers
ORDER BY COUNT(*) OVER (PARTITION BY GardenId) DESC
)
EXEC (N'
;WITH cte As
(
SELECT *, ''Flower'' + CAST(ROW_NUMBER() OVER (PARTITION BY GardenId ORDER BY (SELECT 0)) AS VARCHAR) RN
FROM #Flowers F
)
SELECT Name,' + #ColList + N'
FROM cte
JOIN #Garden g ON g.Id = GardenId
PIVOT (MAX(Flower) FOR RN IN (' + #ColList + N')) Pvt')
DROP TABLE #Garden
DROP TABLE #Flowers
Returns
Name Flower1 Flower2
-------------------- -------------------- --------------------
myGarden rose tulip
yourGarden thistle NULL
Look at using Pivot in SQL Server. Here is a good link that goes over how it works:
http://www.kodyaz.com/articles/t-sql-pivot-tables-in-sql-server-tutorial-with-examples.aspx
Ok, i think i got it working. Try this:
with temp as
(
select 'myGarden' as name, 'test1' as flower
union
select 'myGarden','test2'
union
select 'myGarden','test5'
union
select 'abeGarden','test4'
union
select 'abeGarden','test5'
union
select 'martinGarden', 'test2'
)
select* from temp
pivot
(
max(flower)
for flower in (test1,test2,test3,test4,test5)
) PivotTable
You could also make the values in the in clause dynamic. Since this is a CTE i can't in my example.
Dynamic SQL with a cursor is the only way I can think of, and it won't be pretty.
If you only want the results for one garden at a time this would give you the data:
select gardenName from tblGarden where gardenid = 1
Union ALL
select tblFLowers.flowerName from tblFlowers where gardenid = 1