SQL to combine results into one group in the where clause - sql

I have a query
SELECT name,
COUNT (name)
FROM employee
WHERE LOCATION IS LIKE (%%NY%%)
GROUP BY name
name coount
alex m 10
alex.m 5
alex.ma 1
alex 500
How can I combine all the alex's into just one Alex
so that I get the output as
name count
alex 516
I need something like if it matches alex%% then consider it as alex

Here is your dynamic solution on the below for SQL Server.
First, let's see the sample data I worked on:
create table #temp
(name varchar(20))
insert into #temp values ('jack')
insert into #temp values ('jack rx')
insert into #temp values ('jack.a')
insert into #temp values ('jack.bb')
insert into #temp values ('jack.xy')
insert into #temp values ('brandon.12')
insert into #temp values ('brandon')
insert into #temp values ('brandon.k7s')
insert into #temp values ('brandon.bg')
insert into #temp values ('Jonathan')
Then, we need to employ string operators:
;with cte (name, charin, charin_space) as
(
select name,CHARINDEX('.',name,0) as charin, CHARINDEX(' ',name,0) as charin_space
from #temp
)
select name,(case when charin = 0 and charin_space = 0 then name
when charin = 0 and charin_space <> 0 then SUBSTRING(name,0,charin_space)
when charin <> 0 and charin_space = 0 then SUBSTRING(name,0,charin)
end) as mainName
into #temp2
from cte
The temp table #temp2 has the names only like jack, brandon and jonathan. All we need is to connect those tables now and use group by like:
select t2.MainName,COUNT(t2.MainName)
from #temp t1
inner join #temp2 t2 on t1.name = t2.name
group by t2.mainName
I hope it helps!

You need to get part of the name. But this only work for SQL Server. You don't specify which dbms you are using. The query works with your example, but it will also pick up Alexa, Alexander, ...
SELECT LEFT(name, 4),
SUM(coount)
FROM employee
WHERE LOCATION IS LIKE (%%NY%%)
GROUP BY LEFT(name, 4)

Related

Get result based on Row_number criteria

I have tables three tables: #T, #T1, #Maintable, for which I'll attach the corresponding DDL.
Create table #T ( id int , reason varchar (50));
insert into #T Values (1,'Texas for live music');
insert into #T Values (1,'Texas for BBQ');
insert into #T Values (2,'Wisconsin for dairy products');
insert into #T Values (2,'Wisconsin for Rock');
insert into #T Values (2,'Wisconsin for Bird');
insert into #T Values (3,'North Carolina for Pepsi');
insert into #T Values (4,'Missouri for Forest');
insert into #T Values (5,'Oklohoma for cowboy');
insert into #T Values (5,'Oklohoma for Native Americans');
insert into #T Values (5,'Oklohoma for oil and gas');
Create table #T1 ( id int , reason varchar (50));
insert into #T1 Values (1,'Texas for live music,BBQ');
insert into #T1 Values (2,'Wisconsin for dairy products, rock,bird');
insert into #T1 Values (3,'North Carolina for Pepsi');
insert into #T1 Values (4,'Missouri for Forest');
insert into #T1 Values (5,'Oklohoma for Native Americans,oil and gas');
Create table #MainTable (id int, State varchar(20),Capital varchar(30),Governer varchar(30));
Insert into #Maintable values (1,'Texas','Austin','A');
Insert into #Maintable values (2,'Wisconsin','Madison','B');
Insert into #Maintable values (3,'North Carolina','Releigh','C');
Insert into #Maintable values (4,'Missouri','Jefferson City','D');
Insert into #Maintable values (5,'Oklohoma','Oklohoma city','E');
Expected Output
ID
Reason
State
Capital
Governer
1
Texas for live music,BBQ
Texas
Austin
A
2
Wisconsin for dairy products, rock,bird
Wisconsin
Madison
B
3
North Carolina for Pepsi
North Carolina
Releigh
C
4
Missouri for Forest
Missouri
Jefferson City
D
5
Oklohoma for Native Americans,oil and gas
Oklohoma
Oklohoma city
E
I have a couple of tables, based on the criteria I will be filtering records from table #T and joining with other tables to get more columns but with the help of cte, I am not able to filter. if first table #T has more than one Id then we will be using reason from another table #T1. If it has only one Id then we will be using Reason from Table #T and finally, we will join with #main table to get other records. I have added an image describing more. Help is much appreciated. All those temp tables we can test
And the scenario is:
If reason appears more than once in #T table use #T1 table
If reason appears only once in the #T table use #T only, this is the first table
Here's my coding attempt:
with cte as (
select *, ROW_NUMBER() over (partition by id order by id) rn
from #T
)
select mt.id, state, capital, Governer,
case when c.rn > 1
then #t1.reason
else c.reason
end as reason
from cte c
join #t1 on c.id = #t1.id
join #maintable mt on c.id = mt.id
I am getting more results, I was expecting only 5 records. I guess there is some issue in my row_number. Help is appreciated.
You should first extract the ranking value from the table "#T" for each ID. Then you can use the COALESCE function in combination with LEFT JOIN operations to solve your problem:
WITH #T_ranked AS (
SELECT *, ROW_NUMBER() OVER(PARTITION BY id ORDER BY reason) AS rn
FROM #T
)
SELECT m.id,
COALESCE(#T1.reason, #T_ranked.reason) AS Reason,
m.State,
m.Capital,
m.Governer
FROM #Maintable m
LEFT JOIN #T1 ON m.id = #T1.id
LEFT JOIN #T_ranked ON m.id = #T_ranked.id AND #T_ranked.rn = 1
The LEFT JOIN operations will make your ids in the "MainTable" be kept, while the COALESCE function will make the first non-null argument to be the value for the "Reason" new field, in the specific case it will check whether "#T1.Reason" is null, if it is then it will assign "#T2.Reason". Values from "#T.Reason" which have an existing correspondent in "#T1.Reason" will never be selected in this way.
Check the demo here.

Concatenate multiple rows into single rows and count the concatenated rows in SQL Server

I have a table A:
and I want an output like this:
.
I want to concatenate multiple rows into a single row as well as I want to count how many rows are concatenated..
thanks
use stuff()
select id, stuff(( select concat( ',', name) from tablename b where a.id= b.id
for xml path('')),1,1, ''),count(*) as cnt
from tablename a
group by id
CREATE TABLE #Temp
(ID INT,NAME VARCHAR(50))
INSERT INTO #Temp(ID, [NAME])VALUES(1,'ABC')
INSERT INTO #Temp(ID, [NAME])VALUES(1,'EFG')
INSERT INTO #Temp(ID, [NAME])VALUES(2,'HIJ')
INSERT INTO #Temp(ID, [NAME])VALUES(2,'JKL')
INSERT INTO #Temp(ID, [NAME])VALUES(3,'MNO')
First Created a table....
SELECT t.ID,STUFF(
(
SELECT ',' + s.NAME
FROM #Temp s
WHERE s.ID = t.ID
FOR XML PATH('')),1,1,'') AS NAME,COUNT(t.ID) AS COUNT
FROM #Temp AS t
GROUP BY ID
USE Stuff()

Deleting records that are similar with previous one SQL Server

I am looking for a query which fetches me the data that is different compared to the previous row,
A sample code (with table creation and data)
create table #temp
(id int, eid int, name char(10),estid int, ecid int, epid int, etc char(5) )
insert into #temp values (1,1,'a',1,1,1,'a')
insert into #temp values (2,1,'a',1,1,1,'a')
insert into #temp values (3,1,'a',2,1,1,'a')
insert into #temp values (4,1,'a',1,1,1,'a')
insert into #temp values (5,1,'a',1,1,1,'a')
insert into #temp values (6,1,'a',1,2,1,'a')
insert into #temp values (7,1,'a',1,1,1,'a')
insert into #temp values (8,1,'a',2,1,1,'a')
insert into #temp values (9,1,'a',1,1,1,'a')
insert into #temp values (10,1,'a',1,1,1,'a')
insert into #temp values (11,2,'a',1,1,1,'a')
insert into #temp values (12,2,'a',1,1,1,'a')
insert into #temp values (13,2,'a',2,1,1,'a')
insert into #temp values (14,2,'a',1,1,1,'a')
insert into #temp values (15,2,'a',1,1,1,'a')
insert into #temp values (16,2,'a',1,2,1,'a')
insert into #temp values (17,2,'a',1,1,1,'a')
insert into #temp values (18,2,'a',2,1,1,'a')
insert into #temp values (19,2,'a',1,1,1,'a')
insert into #temp values (20,2,'a',1,1,1,'a')
I tried with some ways of getting the data as the way that i expected
SELECT * INTo #Temp_Final
FROM #temp
WHERE #temp.%%physloc%%
NOT IN (SELECT Min(b.%%physloc%%)
FROM #temp b
GROUP BY eid,name,estid,ecid,epid,etc)
ORDER BY id
SELECT * FROM #temp WHERE id not in (SELECT id FROM #Temp_Final) ORDER BY id
But i wasn't getting the result as i expected...
This is how the result needs to be
select * from #temp where id in (1,3,4,6,7,8,9,11,13,14,16,17,18,19)
You can do this with a simple self-join and appropriate comparison:
select t.*
from #temp t left outer join
#temp tprev
on t.id = tprev.id + 1
where tprev.id is null or
t.name <> tprev.name or
t.estid <> tprev.estid or
t.ecid <> tprev.ecid or
t.epid <> tprev.epid or
t.etc <> tprev.etc;
This assumes that the ids are sequential with no gaps. If the ids are not, you can get the previous id using a correlated subquery or the lag() function.
Your title says "delete" but the question seems to just want the list of such rows. You can phrase this as a delete query if you need to.
For SQL Server 2012 (SQL Fiddle)
WITH CTE
AS (SELECT *,
LAG(eid) OVER (ORDER BY id) AS prev_eid,
LAG(name) OVER (ORDER BY id) AS prev_name,
LAG(estid) OVER (ORDER BY id) AS prev_estid,
LAG(ecid) OVER (ORDER BY id) AS prev_ecid,
LAG(epid) OVER (ORDER BY id) AS prev_epid,
LAG(etc) OVER (ORDER BY id) AS prev_etc
FROM #temp)
DELETE FROM CTE
WHERE EXISTS (SELECT eid,
name,
estid,
ecid,
epid,
etc
INTERSECT
SELECT prev_eid,
prev_name,
prev_estid,
prev_ecid,
prev_epid,
prev_etc)
select
t.id,
t.eid,
t.name,
t.estid,
t.ecid,
t.epid,
t.etc
from #temp t
left join #temp d
on d.id = t.id-1
and d.eid = t.eid
and d.name = t.name
and d.estid = t.estid
and d.ecid = t.ecid
and d.epid = t.epid
and d.etc = t.etc
where d.id is null

SQL Server Simple Group by query

I have a simple problem , Although i believe its simple , am not able to figure out the same.
Consider i have the below table with exactly same data as given below :
CREATE TABLE #temp
(
link varchar(255),
number INT,
fname varchar(255)
)
insert into #temp VALUES ('abc',1,'f1')
insert into #temp VALUES ('abc',2,'f2')
insert into #temp VALUES ('abc',3,'f3')
insert into #temp VALUES ('abc',4,'f6')
insert into #temp VALUES ('abc',10,'f100')
insert into #temp VALUES ('abe',-1,'f0')
insert into #temp VALUES ('abe',1,'f1')
insert into #temp VALUES ('abe',2,'f2')
insert into #temp VALUES ('abe',3,'f3')
insert into #temp VALUES ('abe',4,'f6')
insert into #temp VALUES ('abe',20,'f200')
insert into #temp VALUES ('cbe',-1,'f0')
insert into #temp VALUES ('cbe',1,'f1')
insert into #temp VALUES ('cbe',2,'f2')
insert into #temp VALUES ('cbe',3,'f3')
Now for a given link , i need to get the max 'number' and the corresponding 'fname' which has the max 'number' for the given 'link'.
1)Ex : if link is 'abc' , output should be
abc, 10, f100
2)Ex : if link if 'abe' , Output should be
abe, 20, f200
3)Now link can be also given as a pattern , like (link like 'ab%') , so output should be
abc, 10, f100
abe, 20, f200
4)if (link like 'cb%') , so output should be
cbe, 3, f3
Any help in writing this group by query. I have a solution using CAST and string concat like below , but that seems to be in-efficient.
select link,number,fname from #temp
where link like 'ab%' and link+'_'+CAST(number AS varchar(255))
in (select link+'_'+CAST(MAX(number) AS varchar(255)) from #temp
group by link)
Thanks..
Using a self join:
SELECT x.link,
x.number,
x.fname
FROM #temp x
JOIN (SELECT t.link,
MAX(t.number) AS max_number
FROM #temp t
GROUP BY t.link) y ON y.link = x.link
AND y.max_number = x.number
Using a CTE and ROW_NUMBER (SQL Server 2005+):
WITH cte AS (
SELECT x.link,
x.number,
x.fname,
ROW_NUMBER() OVER(PARTITION BY x.link
ORDER BY x.number DESC) rank
FROM #temp x)
SELECT c.link,
c.number,
c.fname
FROM cte c
WHERE c.rank = 1

Select records with order of IN clause

I have
SELECT * FROM Table1 WHERE Col1 IN(4,2,6)
I want to select and return the records with the specified order which i indicate in the IN clause
(first display record with Col1=4, Col1=2, ...)
I can use
SELECT * FROM Table1 WHERE Col1 = 4
UNION ALL
SELECT * FROM Table1 WHERE Col1 = 6 , .....
but I don't want to use that, cause I want to use it as a stored procedure and not auto generated.
I know it's a bit late but the best way would be
SELECT *
FROM Table1
WHERE Col1 IN( 4, 2, 6 )
ORDER BY CHARINDEX(CAST(Col1 AS VARCHAR), '4,2,67')
Or
SELECT CHARINDEX(CAST(Col1 AS VARCHAR), '4,2,67')s_order,
*
FROM Table1
WHERE Col1 IN( 4, 2, 6 )
ORDER BY s_order
You have a couple of options. Simplest may be to put the IN parameters (they are parameters, right) in a separate table in the order you receive them, and ORDER BY that table.
The solution is along this line:
SELECT * FROM Table1
WHERE Col1 IN(4,2,6)
ORDER BY
CASE Col1
WHEN 4 THEN 1
WHEN 2 THEN 2
WHEN 6 THEN 3
END
select top 0 0 'in', 0 'order' into #i
insert into #i values(4,1)
insert into #i values(2,2)
insert into #i values(6,3)
select t.* from Table1 t inner join #i i on t.[in]=t.[col1] order by i.[order]
Replace the IN values with a table, including a column for sort order to used in the query (and be sure to expose the sort order to the calling application):
WITH OtherTable (Col1, sort_seq)
AS
(
SELECT Col1, sort_seq
FROM (
VALUES (4, 1),
(2, 2),
(6, 3)
) AS OtherTable (Col1, sort_seq)
)
SELECT T1.Col1, O1.sort_seq
FROM Table1 AS T1
INNER JOIN OtherTable AS O1
ON T1.Col1 = O1.Col1
ORDER
BY sort_seq;
In your stored proc, rather than a CTE, split the values into table (a scratch base table, temp table, function that returns a table, etc) with the sort column populated as appropriate.
I have found another solution. It's similar to the answer from onedaywhen, but it's a little shorter.
SELECT sort.n, Table1.Col1
FROM (VALUES (4), (2), (6)) AS sort(n)
JOIN Table1
ON Table1.Col1 = sort.n
I am thinking about this problem two different ways because I can't decide if this is a programming problem or a data architecture problem. Check out the code below incorporating "famous" TV animals. Let's say that we are tracking dolphins, horses, bears, dogs and orangutans. We want to return only the horses, bears, and dogs in our query and we want bears to sort ahead of horses to sort ahead of dogs. I have a personal preference to look at this as an architecture problem, but can wrap my head around looking at it as a programming problem. Let me know if you have questions.
CREATE TABLE #AnimalType (
AnimalTypeId INT NOT NULL PRIMARY KEY
, AnimalType VARCHAR(50) NOT NULL
, SortOrder INT NOT NULL)
INSERT INTO #AnimalType VALUES (1,'Dolphin',5)
INSERT INTO #AnimalType VALUES (2,'Horse',2)
INSERT INTO #AnimalType VALUES (3,'Bear',1)
INSERT INTO #AnimalType VALUES (4,'Dog',4)
INSERT INTO #AnimalType VALUES (5,'Orangutan',3)
CREATE TABLE #Actor (
ActorId INT NOT NULL PRIMARY KEY
, ActorName VARCHAR(50) NOT NULL
, AnimalTypeId INT NOT NULL)
INSERT INTO #Actor VALUES (1,'Benji',4)
INSERT INTO #Actor VALUES (2,'Lassie',4)
INSERT INTO #Actor VALUES (3,'Rin Tin Tin',4)
INSERT INTO #Actor VALUES (4,'Gentle Ben',3)
INSERT INTO #Actor VALUES (5,'Trigger',2)
INSERT INTO #Actor VALUES (6,'Flipper',1)
INSERT INTO #Actor VALUES (7,'CJ',5)
INSERT INTO #Actor VALUES (8,'Mr. Ed',2)
INSERT INTO #Actor VALUES (9,'Tiger',4)
/* If you believe this is a programming problem then this code works */
SELECT *
FROM #Actor a
WHERE a.AnimalTypeId IN (2,3,4)
ORDER BY case when a.AnimalTypeId = 3 then 1
when a.AnimalTypeId = 2 then 2
when a.AnimalTypeId = 4 then 3 end
/* If you believe that this is a data architecture problem then this code works */
SELECT *
FROM #Actor a
JOIN #AnimalType at ON a.AnimalTypeId = at.AnimalTypeId
WHERE a.AnimalTypeId IN (2,3,4)
ORDER BY at.SortOrder
DROP TABLE #Actor
DROP TABLE #AnimalType
ORDER BY CHARINDEX(','+convert(varchar,status)+',' ,
',rejected,active,submitted,approved,')
Just put a comma before and after a string in which you are finding the substring index or you can say that second parameter.
And first parameter of CHARINDEX is also surrounded by , (comma).