Convert from single column to multiple Column in sql Server - sql

i have tried with below code. but i didnt get ouput as per multiple column.
select Name=stuff((select ','+
name from Input t1 WHERE t1.Name=t2.name for xml path('')),1,9,''),NAME
=stuff((select ','+
name from Input t1 WHERE t1.Name=t2.name for xml path('')),1,1,'')FROM
Input T2
GROUP BY NAME

I have separated the character and numeric parts of the given string in CTE and used a simple group by and sum clause on that.
;With CTE
As
(
Select
Left(Names, 1) As String,
SUBSTRING(Names, 2, Len(Names) - 1) As Number
From SeparateColumns
)
Select
String,
Sum(Cast(Number As Int)) As SumOfDigits
From CTE
Group By String
Order By String;

Assuming you will have single character in your column, the following code works
CREATE TABLE #TEMP_SPLIT
(VALUE VARCHAR(25))
INSERT INTO #TEMP_SPLIT
SELECT 'A10'
UNION
SELECT 'B20'
UNION
SELECT 'A30'
UNION
SELECT 'B40'
UNION
SELECT 'A10'
UNION
SELECT 'C1'
SELECT c, sum(tot)
FROM
(
SELECT SUBSTRING(VALUE,1,1) c ,CONVERT(FLOAT,SUBSTRING(VALUE,2,LEN (VALUE)-1)) Tot
FROM #TEMP_SPLIT
)T
GROUP BY C
DROP TABLE #TEMP_SPLIT

If the names column is always in the specified format, then use LEFT function to extract the character part and RIGHT function to extract the digits part and use these two in the sub-query and use GROUP BY clause and SUM function.
Query
select t.col_a as [string character],
sum(cast(t.col_b as int)) as [sum of digits] from(
select left(names, 1) as col_a,
right(names, len(names) - 1) as col_b
from [your_table_name]
) t
group by t.col_a;
Find a example here

You could use PATINDEX() with SUBSTRING() function if names always in this specified format
select A.CHAR [Strings], SUM(CAST(A.VALUE AS INT)) [Sum] from
(
SELECT SUBSTRING(Name, 1, PATINDEX('%[^A-Z]%', Name)-1) [CHAR], SUBSTRING(Name, PATINDEX('%[0-9]%', Name), len(Name)) [VALUE] FROM <table>
) a GROUP BY A.CHAR

Here's simple solution using subquery and group by clause:
select [StringChar], SUM([Number]) from (
select SUBSTRING(Names, 1, 1) as [StringChar],
convert(int, SUBSTRING(Names, 2, LEN(Names))) as [Number]
from [Input]
) as a group by [StringChar]

Related

Split comma delimited names in Microsoft Report Builder

In my database, I have a column, which lists names. Names are in this format:
surname, first name, surname, first name
e.g: bloggs, joe, jackson, samuel
I'm assuming I will use a 'split' expression, but how do I write it so that it appears in my report as:
surname, first name
surname, first name
Thanks
test table
declare #t table(ch varchar(max))
insert into #t values('bloggs, joe, jackson, samuel')
your query PARSENAME(REPLACE) divide your table into columns based on character after , like
SELECT
PARSENAME(REPLACE(ch,',','.'),4) 'Surname1' ,
PARSENAME(REPLACE(ch,',','.'),3) 'FirstName1',
PARSENAME(REPLACE(ch,',','.'),2) 'Surname2',
PARSENAME(REPLACE(ch,',','.'),1) 'FirstName2'
FROM #t
then use union in order to put it in columns, or concat to put your value in a single column.
SELECT
concat(
PARSENAME(REPLACE(ch,',','.'),4),',',
PARSENAME(REPLACE(ch,',','.'),3) )'Names'
FROM #t
UNION all
SELECT
concat(
PARSENAME(REPLACE(ch,',','.'),2),',',
PARSENAME(REPLACE(ch,',','.'),1) )'Names'
from #t
if your column has more than two name then use updated syntax with descending order
------------(K) Ordered Pair--------------
SELECT
concat(
PARSENAME(REPLACE(ch,',','.'),2K),',',
PARSENAME(REPLACE(ch,',','.'),2K-1) )'Names'
FROM #t
UNION all
------------(K-1) Ordered Pair-------------
SELECT
concat(
PARSENAME(REPLACE(ch,',','.'),2K-2),',',
PARSENAME(REPLACE(ch,',','.'),2K-3) )'Names'
from #t
/*--------------------------------------*/
/*--------------------------------------*/
/*--------------------------------------*/
------------(2) Ordered Pair--------------
SELECT
concat(
PARSENAME(REPLACE(ch,',','.'),4),',',
PARSENAME(REPLACE(ch,',','.'),3) )'Names'
FROM #t
UNION all
------------(1) Ordered Pair--------------
SELECT
concat(
PARSENAME(REPLACE(ch,',','.'),2),',',
PARSENAME(REPLACE(ch,',','.'),1) )'Names'
from #t
The other-way is using string_split to split charchter,NTILE to give it rank and string_agg to results into one column that enables you to have more than 2 names
select string_agg(value,',') from
(
SELECT
value , NTILE (2) OVER (
ORDER BY value
) ID
FROM #t
cross apply
STRING_SPLIT(ch, ',')) t
group by ID

Group by value extracted from function

I am trying to group by a value extracted from a function. [fnSplitter] extracts the second delimiter from "123-456-459-905". In other words, it extracts "456". I alias the second delimiter as [Col_B] and I would like to group by it. Is this possible?
select
(
select data
from [fnSpliter] (REPLACE ((REPLACE (pk, '-', '|')),'||', '|-'), '|')
where id = 2
) as [Col_B]
from [Table]
group by [Col_B]
You can't group by an alias. So se apply:
select f.data as col_b
from [Table] t cross apply
[fnSpliter](REPLACE(REPLACE(pk, '-', '|'), '||', '|-'), '|') f
where f.id = 2
group by f.data
Assuming that you have a scalar function, as your question suggests, you could select the values in a subquery, than group by in the outer query:
select [Col_B]
from (
select dbo.[fnSpliter](REPLACE ((REPLACE (pk, '-', '|')),'||', '|-'), '|') as [Col_B]
from [Table]
where id = 2
) t
group by [Col_B]
Note that the name of the function should be prefixed with the schema it belongs to - I assumed dbo.
The example hardly makes sense. In a real query, you would likely use an aggregate function in the outer query (such as COUNT(*) for example).

I want to retrieve max value from two column - SQL table

Please find attached image for table structure
You could try using UNION ALL for build a unique column result and select the max from this
select max(col)
from (
select col1 col
from trans_punch
union all
select col2
from trans_punch) t
You can use a common table expression to union the columns, then select the max.
;with cteUnionPunch(Emp_id, both_punch) AS
(
SELECT Emp_id, In_Punch FROM trans_punch
UNION ALL
SELECT Emp_id, Out_Punch FROM trans_punch
)
SELECT Emp_id, max(both_punch) FROM cteUnionPunch GROUP BY Emp_id
You can use apply :
select tp.Emp_id, max(tpp.Punchs)
from trans_punch as tp cross apply
( values (In_Punch), (Out_Punch) ) tpp(Punchs)
group by tp.Emp_id;

SQL Server - Sorting column based on string and number

I have a table with one column which contains combination of string and number like as shown below. I need to sort the name column in descending or ascending but the problem is when I use ORDER BY it is not sorting as expected
My query is like as shown below
SELECT * FROM test ORDER BY `name` ASC
My expected result is like as shown blow
employee1
employee2
employee3
employee6
employee6
employee10
employee11
employee12
employee17
employee82
employee100
employee111
employee129
employee299
Can anyone please help me on this
You can try below by only extracting the number part from the field
SELECT * FROM test
ORDER BY cast(replace(`name`,'employee','') as int) ASC
Please try the code below:
-- ASSUMES NUMBERS ARE IN THE LAST CHARACTER
-- WONT WORK IF NUMBER IS THERE IN THE MIDDLE
DROP TABLE IF EXISTS #data
select
Name = REPLACE(name,' ','')
,NameWithNum = REPLACE(name,' ','') + cast(object_id as varchar(100))
INTO #data
from sys.tables
SELECT
NameWithNum
,NameRemovedNumbers= SUBSTRING(NameWithNum, PATINDEX('%[0-9]%', NameWithNum), LEN(NameWithNum))
from #data
ORDER BY Name,SUBSTRING(NameWithNum, PATINDEX('%[0-9]%', NameWithNum), LEN(NameWithNum))
Since the number always in the end, you can do as
WITH CTE AS
(
SELECT 'employee1' Name
union all select 'employee2'
union all select 'employee3'
union all select 'employee6'
union all select 'employee6'
union all select 'employee10'
union all select 'employee11'
union all select 'employee12'
union all select 'employee17'
union all select 'employee82'
union all select 'employee100'
union all select 'employee111'
union all select 'employee129'
union all select 'employee299'
)
SELECT Name
FROM CTE
ORDER BY CAST(SUBSTRING(Name, PATINDEX('%[^a-z, '' '']%', Name), LEN(Name)) AS INT)
--OR PATINDEX('%[0-9]%', Name)
Or
WITH CTE AS
(
SELECT 'The First Employee 1' Name
union all select 'The Second One 2'
union all select 'Employee Number 4'
union all select 'Employee Number 3'
)
SELECT Name
FROM CTE
ORDER BY CAST(SUBSTRING(Name, PATINDEX('%[0-9]%', Name), LEN(Name)) AS INT)
Here is a Live Demo where you can change the strings and see the results.
Finnaly, I would note to the real problem, which is a table with just one column and no PK.
The "base" part of the name is the same. So, you can order by the length and then the name:
SELECT t.*
FROM test t
ORDER BY LEN(name), name;

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