How to show query result in group? SQL Query - sql

Right now my sql query display the result as follows.
though it is the correct result.
I prefer to have the have the result to show as follows.
How can I do this with SQL ? I am on SQL server 2008

I'm with the commenters, better to do this elsewhere, but it's simple enough in SQL using a CASE statement and the ROW_NUMBER() function:
;WITH cte AS (SELECT *,ROW_NUMBER() OVER (PARTITION BY ID ORDER BY (SELECT 1)) RN
FROM YourTable)
SELECT CASE WHEN RN = 1 THEN CAST(ID AS VARCHAR(5)) ELSE '' END, Name
FROM cte
ORDER BY ID,RN
Demo: SQL Fiddle

This is not a job for SQL.
Any way, you can easily display it with comma separated values:
ID Names
1000 Honda, Toyota,...
1000 Honda, Toyota,...
SELECT ID, Names=
STUFF((SELECT ', ' + Name
FROM your_table b
WHERE b.ID= a.ID
FOR XML PATH('')), 1, 2, '')
FROM your_table a
GROUP BY ID

Related

SQL: Count of items in comma-separated column in a table

Column1
--------
1,2,4
2,3,5
2,1,3
I have a column in a table which is comma-separated as shown above. From which I need to get below output:
No Count
----------
1 2
2 3
3 2
4 1
When I tried with
SELECT SUM(LEN(Holidays) - LEN(REPLACE(Holidays, ',', '')) + 1)
FROM [dbo].[OhLog]
I'm not getting item wise count. Instead it is getting full count.
You can use CROSS_APPLY with STRING_SPLIT to create rows from the comma separated data values, and then COUNT the occurrences of each value:
SELECT value as [Holiday], COUNT(*) AS [Count]
FROM OhLog
CROSS APPLY STRING_SPLIT([Holidays], ',')
GROUP BY value
Output:
Holiday Count
1 2
2 3
3 2
4 1
5 1
Demo on dbfiddle
If your database compatibility version is not at least 130, you won't have access to STRING_SPLIT. You can modify the compatibility version as described in the manual, or alternatively, use this query (based on this answer):
SELECT [Holiday], COUNT(*) AS [Count]
FROM (SELECT Split.a.value('.', 'NVARCHAR(MAX)') [Holiday]
FROM (SELECT CAST('<X>'+REPLACE([Holidays], ',', '</X><X>')+'</X>' AS XML) AS String
FROM Ohlog
) AS A
CROSS APPLY String.nodes('/X') AS Split(a)) AS O
GROUP BY [Holiday]
Output is the same as for the prior query. Demo on dbfiddle
Please try:
SELECT
Num, count(*) Cnt from
(
SELECT
LTRIM(RTRIM(m.n.value('.[1]','varchar(8000)'))) AS Num
FROM
(
SELECT CAST('<XMLRoot><RowData>' + REPLACE(Column1,',','</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) AS x
FROM tbl
)t
CROSS APPLY x.nodes('/XMLRoot/RowData')m(n)
)x
GROUP BY Num
Demo Result
So, you can use STRING_SPLIT function. It is supported by Sql Server 2017.
more info here http://www.sqlservertutorial.net/sql-server-string-functions/sql-server-string_split-function/
It creates a table from string.
So, for each row in DB you will get a table. To Union it into one common table you have to use CROSS APPLY.
SELECT VALUE, COUNT(*) FROM test_for_parse CROSS APPLY STRING_SPLIT(array_value,',') GROUP BY VALUE
So, here is an example of code, that emulate your situation.
https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=8393f8dab667b528ed5aad7c61da74fe

TSQL get column names from dynamic query with formatting/conditions

I need to identify list of columns and its original value from dynamic SQL.
Example: I have this SQL statement:
#tsql = N'SELECT A.ID AS PROCESSID, COALESCE(STEP_ID,'''') AS programmid, NAME FROM DBO.TBL_LOG A'
As per this solution It will just return column name. I need both column name and its original value.
Expected result :
Can anyone please help with this? Thank you in advance.
Below code works for me temporary , If there will be too complex statement in select clause than it will not work.
;WITH CTE AS
(
SELECT NAME , SUBSTRING(LTRIM(#TSQL),7,CHARINDEX('FROM',LTRIM(#TSQL),0)-7) as QRY FROM sys.dm_exec_describe_first_result_set (#TSQL, null, 0)
)
,COLPOS as
(
select NAME,QRY, CHARINDEX(NAME ,QRY,LEN(QRY) - CHARINDEX(REVERSE(NAME),REVERSE(QRY),0)- LEN(NAME)) AS POS
FROM CTE
)
,POS AS (
SELECT NAME,QRY,POS,LAG(POS) OVER (order by (select 1)) LGPOS,LEAD(POS) OVER (order by (select 1)) LEADPOS
,LAG(NAME) OVER (order by (select 1)) LGNAME
FROM COLPOS
)
SELECT NAME , LTRIM(RTRIM(SUBSTRING (QRY,COALESCE(LGPOS+LEN(LGNAME),0),POS+LEN(NAME)-COALESCE(LGPOS+LEN(LGNAME),0)))) AS EXPRESSION
FROM POS

SQL - multi select query returning no results

I have a query where I'm trying to select a Row Number from a table that meets a certain criteria from a separate table.
The current query returns 0 results when I'm expecting 1 number
SELECT
RowNum
FROM
(SELECT
ID, Name, RowNum = ROW_NUMBER() OVER (ORDER BY ID)
FROM
tblEncroachmentTypes) AS temp
WHERE
temp.Name LIKE (SELECT EN_TYPE
FROM LakeEncroachments
WHERE EN_ID = '0526')
I have created a temp table to try and simplify it, but it still returns no results
select RowNum
from #temp1
where #temp1.Name like (select EN_TYPE from LakeEncroachments where EN_ID = '0526')
I'm trying to give as much information as possible, but not sure what else I need.
If you need to use like, you might need to add the wildcards:
SELECT RowNum
from (Select ID, Name, RowNum = ROW_NUMBER() over (order by ID) from tblEncroachmentTypes) as temp
where temp.Name Like '%'+(Select EN_TYPE from LakeEncroachments WHERE EN_ID = '0526')+'%'
reformat looks like this:
select RowNum
from (
select ID
, name
, RowNum = row_number() over (
order by ID
)
from tblEncroachmentTypes
) as temp
where temp.name like '%' + (
select EN_TYPE
from LakeEncroachments
where EN_ID = '0526'
) + '%'
Also, if your sub query for like returns more than one value, you'll need a different approach.
if your subquery give multiple rows, use this query
WITH temp as
(SELECT ID, Name, ROW_NUMBER() OVER (ORDER BY ID) as RowNum
FROM tblEncroachmentTypes) AS temp
SELECT temp.RowNum
FROM LakeEncroachments
INNER JOIN temp ON temp.Name LIKE REPLACE(REPLACE(LakeEncroachments.EN_TYPE, '-', '% '), ' ', '% ') + '%'
WHERE EN_ID = '0526'

How to display all but first table row?

Is it possible to display all but first row from a table in sql server 2005?
I have this data:
---------------------------------
| ID | Name |
---------------------------------
| 1 | John Smith |
| 2 | John Doe |
| 3 | John Thatcher |
---------------------------------
In my query I need to be able to get 'John Doe' and 'John Thatcher'. I Don't need 'ID' column to be displayed, so I can't use ROW_NUMBER here like follows:
select Name from Customers where ROW_NUMBER() over (order by Id)>1
Please advice.
Thank you.
UPDATE:
Clarification: I would like my query to return only Name column but I can't use table expressions, because I'm using the query as part of string concatenation:
select stuff((select ', '+pfn.FullName from PlaintiffsFullNameView pfn where pfn.SuitId=s.Id for xml path('')),1,1,'') as "CoPlaintiffs"
Now I need to transform this query to return all but first plaintiff in a concatenated manner.
UPDATE 2:
Sorry for messed up explanation, let me try it anew:
I have a suits table and a plaintiffs table. (one to many)
I have a requirement to display each suit with all coplaintiffs concatenated.
"Coplaintiff" is any but first suit plaintiff. I can concatenate all plaintiffs and display them along with corresponding suit data (all in one row), but I can't to figure out how to concatenate all coplaintiffs and display them as string in a row column.
SELECT Name
FROM (
SELECT Name, ROW_NUMBER() OVER (ORDER BY id) AS rn
FROM Customers
) q
WHERE rn > 1
ORDER BY
id
Update:
From your explanation:
SELECT Suit.*,
FirstPlantiff.*,
(
SELECT cp.Name AS [text()]
FROM Plantiff cp
WHERE cp.id <> FirstPlantiff.id
AND cp.SuitID = Suid.ID
ORDER BY
cp.id
FOR XML PATH('')
) AS Coplantiffs
FROM Suit
CROSS APPLY
(
SELECT TOP 1 *
FROM Plantiff p
WHERE p.SuitID = Suit.ID
ORDER BY
p.id
) FirstPlantiff
SELECT Name
FROM Customers
WHERE ID <> (SELECT TOP 1 ID
FROM Customers
ORDER BY ID)
Or since the Id never changes you could just do where ID <> 1
Your query with ROW_NUMBER gives an error, because you can't use ROW_NUMBER in the WHERE clause. So you'd need another subquery:
select stuff((
select ',' + FullName
from (
select pfn.FullName, row_number() over (order by pfn.id) as rn
from #suits s
inner join #plaintiffs pfn on s.id = pfn.SuitId
) sub
where rn <> 1
for xml path('')
), 1, 1, '') subsub
Alternatively, you could select the id of the first row in a subquery:
select stuff((
select ',' + pfn.FullName
from #suits s
inner join #plaintiffs pfn on s.id = pfn.SuitId
where s.id = 1
and pfn.id not in (
select min(id) from #plaintiffs where SuitId = s.id)
for xml path('')
), 1, 1, '') sub
Here's the code segment to generate test data:
declare #suits table (id int identity, CaseName varchar(max))
insert into #suits (CaseName) values ('The People v.s. Donald Duck')
declare #plaintiffs table (id int identity,
SuitId int, FullName varchar(max))
insert into #plaintiffs (SuitId,Fullname)
select 1, 'John Smith'
union all select 1, 'John Doe'
union all select 1, 'John Thatcher'
Your query should work, there's no need for Id to be returned for it to be used in the WHERE condition.
Also, maybe this page can help.
SELECT * FROM Customers
EXCEPT SELECT TOP 1 * FROM Customers
Try these
Solution 1:
select name
from #tbl
where id <> 1
Solution 2:
select top(select count(name) -1 from #tbl) name
from #tbl
order by id desc

SQL Server Top 1

In Microsoft SQL Server 2005 or above, I would like to get the first row, and if there is no matching row, then return a row with default values.
SELECT TOP 1 ID,Name
FROM TableName
UNION ALL
SELECT 0,''
ORDER BY ID DESC
This works, except that it returns two rows if there is data in the table, and 1 row if not.
I'd like it to always return 1 row.
I think it has something to do with EXISTS, but I'm not sure.
It would be something like:
SELECT TOP 1 * FROM Contact
WHERE EXISTS(select * from contact)
But if not EXISTS, then SELECT 0,''
What happens when the table is very full and you might want to specify which row of your top 1 to get, such as the first name? OMG Ponies' query will return the wrong answer in that case if you just change the ORDER BY clause. His query also costs about 8% more CPU than this modification (though it has equal reads)
SELECT TOP 1 *
FROM (
SELECT TOP 1 ID,Name
FROM TableName
ORDER BY Name
UNION ALL
SELECT 0,''
) X
ORDER BY ID DESC
The difference is that the inner query has a TOP 1 also, and which TOP 1 can be specified there (as shown).
Just for fun, this is another way to do it which performs very closely to the above query (-15ms to +30ms). While it's more complicated than necessary for such a simple query, it demonstrates a technique that I don't see other SQL folks using very often.
SELECT
ID = Coalesce(T.ID, 0),
Name = Coalesce(T.Name, '')
FROM
(SELECT 1) X (Num)
LEFT JOIN (
SELECT TOP 1 ID, Name
FROM TableName
ORDER BY ID DESC
) T ON 1 = 1 -- effective cross join but does not limit rows in the first table
Use:
SELECT TOP 1
x.id,
x.name
FROM (SELECT t.id,
t.name
FROM TABLENAME t
UNION ALL
SELECT 0,
'') x
ORDER BY id DESC
Using a CTE equivalent:
WITH query AS (
SELECT t.id,
t.name
FROM TABLENAME t
UNION ALL
SELECT 0,
'')
SELECT TOP 1
x.id,
x.name
FROM query x
ORDER BY x.id DESC
CREATE TABLE #sample(id INT, data VARCHAR(10))
SELECT TOP 1 id, data INTO #temp FROM #sample
IF ##ROWCOUNT = 0 INSERT INTO #temp VALUES (null, null)
SELECT * FROM #temp
put the top oustide of the UNION query
SELECT TOP 1 * FROM(
SELECT ID,Name
FROM TableName
UNION ALL
SELECT 0,''
) z
ORDER BY ID DESC
IF EXISTS ( SELECT TOP 1 ID, Name FROM TableName )
BEGIN
SELECT TOP 1 ID, Name FROM TableName
END
ELSE
BEGIN
--exists returned no rows
--send a default row
SELECT 0, ''
END