SQL Server T-SQL concat aggregate - sql-server

Imagine I have this table
BirthDay |Name
1-10-2010 | 'Joe'
2-10-2010 | 'Bob'
2-10-2010 | 'Alice'
How can I get a result like this
BirthDay |Name
1-10-2010 | 'Joe'
2-10-2010 | 'Bob', 'Alice
tks

try this:
set nocount on;
declare #t table (BirthDay datetime, name varchar(20))
insert into #t VALUES ('1-10-2010', 'Joe' )
insert into #t VALUES ('2-10-2010', 'Bob' )
insert into #t VALUES ('2-10-2010', 'Alice')
set nocount off
SELECT p1.BirthDay,
stuff(
(SELECT
', ' + p2.name --use this if you want quotes around the names: ', ''' + p2.name+''''
FROM #t p2
WHERE p2.BirthDay=p1.BirthDay
ORDER BY p2.name
FOR XML PATH('')
)
,1,2, ''
) AS Names
FROM #t p1
GROUP BY
BirthDay
OUTPUT:
BirthDay Names
----------------------- ------------
2010-01-10 00:00:00.000 Joe
2010-02-10 00:00:00.000 Alice, Bob
(2 row(s) affected)

This solution works with no need of deploy from Visual studio or dll file in server.
Copy-Paste and it Work!
http://groupconcat.codeplex.com/
dbo.GROUP_CONCAT(VALUE )
dbo.GROUP_CONCAT_D(VALUE ), DELIMITER )
dbo.GROUP_CONCAT_DS(VALUE , DELIMITER , SORT_ORDER )
dbo.GROUP_CONCAT_S(VALUE , SORT_ORDER )

Related

Get the max number in a varchar column SQL Server

I have a varchar column which holds comma separated numbers.
I want to fetch the max number in that column.
+-------------------+--------------+
| reference_no | Name |
+-------------------|--------------+
| 17530, 20327 | John |
| , 14864 | Smith |
| 8509 | Michael |
| 14864, 17530 | Kelly |
+-------------------+--------------+
So, in the above column (reference_no) example the output should be 20327.
Then I have to select the row which contains this number.
Assuming NOT 2016+
If you have no more than 4 values in reference_no in any particular row, then perhaps parsename()
If more than 4, you may need to fix the data or use a split/parse function.
Example
Select MaxValue = max(V)
From YourTable A
Cross Apply ( values (replace([reference_no],',','.')) ) B(S)
Cross Apply ( values (try_convert(int,parsename(S,1)))
,(try_convert(int,parsename(S,2)))
,(try_convert(int,parsename(S,3)))
,(try_convert(int,parsename(S,4)))
) C(V)
Returns
MaxValue
20327
try the following:
declare #tab table (reference_no varchar(max), [Name] varchar(100))
insert into #tab
select '17530, 20327','John' union
select ', 14864 ','Smith' union
select '8509 ','Michael' union
select '14864, 17530','Kelly'
create table #final (val int)
insert into #final
SELECT Split.a.value('.', 'VARCHAR(100)') AS String
FROM (SELECT reference_no reference_no,
CAST ('<S>' + REPLACE(reference_no, ',', '</S><S>') + '</S>' AS XML) AS String
FROM #tab) AS A CROSS APPLY String.nodes ('/S') AS Split(a);
select * from #tab where reference_no like '%'+ (select convert(varchar(100), max(val)) from #final) + '%'
drop table #final

SQL Server 2012: Check for Duplicates with Criteria

On SQL Server 2012, I have a table which is similar as below:
Id | SessionId | TypeId | Operation | Data
------------------------------------------------------------------------
1 | ABC-123 | 6 | I |<Record EmployeeName="Joe" />
2 | ABC-123 | 6 | U |<Record EmployeeName="Joe" />
For us, the second row is a duplicate (I want to remove the record with the operation 'U' since I have an 'I' operation already) and I want to remove it. However, my SQL I tried actually removes other records also (see below).
;WITH CTE AS (
SELECT [id],
[SessionId],
[TypeId],
[Operation],
[Data],
RN = ROW_NUMBER() OVER (PARTITION BY [SessionId], [Data] ORDER BY [Data])
FROM dbo.MyTable
WHERE SessionId = #sessionId
)
DELETE FROM CTE
WHERE [Operation] = 'U'
Can you help?
DECLARE #t TABLE (
Id INT IDENTITY(1,1) PRIMARY KEY,
SessionId VARCHAR(50),
TypeId INT,
Operation CHAR(1),
Data XML
)
INSERT INTO #t (SessionId, TypeId, Operation, Data)
VALUES
('ABC-123', 6, 'I', '<Record EmployeeName="Joe" />'),
('ABC-123', 6, 'U', '<Record EmployeeName="Joe" />')
;WITH CTE AS (
SELECT *,
RN = ROW_NUMBER() OVER (PARTITION BY [SessionId], CHECKSUM(CAST([Data] AS NVARCHAR(MAX))) ORDER BY Id)
FROM #t
)
DELETE FROM CTE
WHERE RN > 1
AND Operation = 'U'
SELECT * FROM #t
output -
Id SessionId TypeId Operation Data
--- ------------ ----------- --------- ------------------------------
1 ABC-123 6 I <Record EmployeeName="Joe" />

Computing a column based on comparisons of other columns in table

Ok I am working on a database table with 4 columns, lets say a first name, middle name, last name and a group id. I want to group people based on the fact that they have the same first and last names regardless of their middle name. I also want to, if a new entry comes in, give that entry the correct group id.
Here is an example of the result:
----------------------------------------------------------
| First_Name | Middle_Name | Last_Name | Group_ID |
----------------------------------------------------------
| Jon | Jacob | Schmidt | 1 |
----------------------------------------------------------
| William | B. | Schmidt | 1 |
----------------------------------------------------------
| Sally | Anne | Johnson | 2 |
----------------------------------------------------------
I'm not sure whether or not this falls under the jurisdiction of a computed column, some kind of join or something far less obscure, Please help!
If you only need to enumerate the groups within a query then row_number() will work for you:
declare #Names table ( First_Name varchar(10), Middle_Name varchar(10), Last_Name varchar(10))
insert into #Names
select 'Jon', 'Jacob', 'Schmidt' union all
select 'William', 'B.', 'Schmidt' union all
select 'Sally', 'Anne', 'Johnson' union all
select 'Jon', 'Two', 'Schmidt'
;with Groups (First_Name, Last_Name, Group_ID) as
( select First_Name, Last_Name, row_number()over(order by Last_Name)
from #Names
group
by First_Name, Last_Name
)
select n.First_Name, n.Middle_Name, n.Last_Name, g.Group_Id
from #Names n
join Groups g on
n.First_Name = g.First_Name and
n.Last_Name = g.Last_Name;
Be aware the Group_ID value will change as new nameGroups are introduced.
If you want to assign and persist a Group_ID then I would suggest creating an ancillary table and assign the Group_IDs there.
By storing the mapping outside of the #Names table you are allowing users to change their names and not have to worry about re-evaluating the group assignment. It also allows you to modify the grouping logic without re-assigning names. You also have the ability to map similar enough values to the same grouping (John, Jon, Jonny).
Group_ID is composed of a First_Name and Last_Name. So, store it that way.
declare #Names table ( First_Name varchar(10), Middle_Name varchar(10), Last_Name varchar(10))
insert into #Names
select 'Jon', 'Jacob', 'Schmidt' union all
select 'William', 'B.', 'Schmidt' union all
select 'Sally', 'Anne', 'Johnson' union all
select 'Jon', 'Two', 'Schmidt'
declare #NameGroup table (Group_Id int identity(1,1), First_Name varchar(10), Last_Name varchar(10) unique(First_Name, Last_Name));
insert into #NameGroup (First_Name, Last_Name)
select 'Jon', 'Schmidt' union all
select 'Sally', 'Johnson';
declare #Group_ID int;
declare #First_Name varchar(10),
#Middle_Name varchar(10),
#Last_Name varchar(10)
select #First_Name = 'Jon',
#Middle_Name = 'X',
#Last_Name = 'Schmidt'
--be sure the Id has already been assigned
insert into #NameGroup
select #First_Name, #Last_Name
where not exists(select 1 from #NameGroup where First_Name = #First_Name and Last_Name = #Last_Name)
--resolve the id
select #Group_ID = Group_ID
from #NameGroup
where First_Name = #First_Name and
Last_Name = #Last_Name;
--store the name
insert into #Names (First_Name, Middle_Name, Last_Name)
values(#First_Name, #Middle_Name, #Last_Name);
select n.First_Name, n.Middle_Name, n.Last_Name, ng.Group_Id
from #Names n
join #NameGroup ng on
n.First_Name = ng.First_Name and
n.Last_Name = ng.Last_Name;

Dynamic Pivot Tables MS SQL 2008

I'm trying to create a dynamic pivot table to get results in different columns rather than rows.
This is the table I'm using to test
CREATE TABLE [dbo].[Authors](
[Client_Id] [nvarchar](50) NOT NULL,
[Project_Id] [nvarchar](50) NOT NULL,
[Person_Id] [int] NOT NULL,
[Author_Number] [int] NOT NULL,
[Family_Name] [nvarchar](50) NULL,
[First_Name] [nvarchar](50) NULL,
)
INSERT INTO Authors (Client_Id, Project_Id, Person_Id, Author_Number, Family_Name, First_Name)
VALUES ('TEST','TEST',12345,1,'Giust','Fede')
INSERT INTO Authors (Client_Id, Project_Id, Person_Id, Author_Number, Family_Name, First_Name)
VALUES ('TEST','TEST',12345,2,'Giust','Fede')
INSERT INTO Authors (Client_Id, Project_Id, Person_Id, Author_Number, Family_Name, First_Name)
VALUES ('TEST','TEST',12346,1,'Giust','Fede')
INSERT INTO Authors (Client_Id, Project_Id, Person_Id, Author_Number, Family_Name, First_Name)
VALUES ('TEST','TEST',12346,2,'Giust','Fede')
INSERT INTO Authors (Client_Id, Project_Id, Person_Id, Author_Number, Family_Name, First_Name)
VALUES ('TEST','TEST',12346,3,'Giust','Fede')
So far I get the results like this
CLIENT_ID PROJECT_ID PERSON_ID AUTHOR_NUMBER FAMILY_NAME FIRST_NAME
TEST TEST 12345 1 Giust Fede
TEST TEST 12345 2 Ma Ke
TEST TEST 12346 1 Jones Peter
TEST TEST 12346 2 Davies Bob
TEST TEST 12346 3 Richards Craig
I need the results to come out like this, and to be dynamic because sometime I can have 2 authors, or 10 authors.
CLIENT_ID PROJECT_ID PERSON_ID FAMILY_NAME_1 FIRST_NAME_1 FAMILY_NAME_2 FIRST_NAME_2 FAMILY_NAME_3 FIRST_NAME_3
TEST TEST 12345 Giust Fede Ma Ke
TEST TEST 12346 Jones Peter Davies Bob Richards Craig
I've been trying to use this code, but keep getting errors
SQL Fiddle
Here are a few suggestions to solve your issue.
First, your current code is unpivoting all of the columns in the table, you only need to UNPIVOT the Family_Name and First_Name columns. As a result I would not use a variable to get this list of columns, just hard-code the two columns you need to unpivot.
Then to get the list of columns to PIVOT, alter the code to use both the Author_number and then a string with the column names Family_Name and First_Name:
select #colsPivot = STUFF((SELECT ',' + QUOTENAME(c.col + '_'+cast(Author_Number as varchar(10)))
from Authors
cross apply
(
select 'Family_Name' col, 1 so union all
select 'First_Name', 2
) c
group by col, author_number, so
order by author_number, so
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
This gives a list of cols:
| COLUMN_0 |
------------------------------------------------------------------------------------------------
| [Family_Name_1],[First_Name_1],[Family_Name_2],[First_Name_2],[Family_Name_3],[First_Name_3] |
Making these changes to your code the final query will be
DECLARE #colsPivot AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #colsPivot = STUFF((SELECT ',' + QUOTENAME(c.col + '_'+cast(Author_Number as varchar(10)))
from Authors
cross apply
(
select 'Family_Name' col, 1 so union all
select 'First_Name', 2
) c
group by col, author_number, so
order by author_number, so
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query
= 'select Client_id, Project_id, Person_Id, '+#colsPivot+'
from
(
select Client_id, Project_id, Person_Id,
col+''_''+cast(Author_Number as varchar(10)) col, val
from
(
select Client_id, Project_id,
Person_Id,
Author_Number,
Family_Name,
First_Name
from Authors
) s
unpivot
(
val
for col in (Family_Name, First_Name)
) u
) x1
pivot
(
max(val)
for col in ('+ #colspivot +')
) p'
exec(#query)
See SQL Fiddle with Demo. This gives a result:
| CLIENT_ID | PROJECT_ID | PERSON_ID | FAMILY_NAME_1 | FIRST_NAME_1 | FAMILY_NAME_2 | FIRST_NAME_2 | FAMILY_NAME_3 | FIRST_NAME_3 |
-----------------------------------------------------------------------------------------------------------------------------------
| TEST | TEST | 12345 | Giust | Fede | Ma | Ke | (null) | (null) |
| TEST | TEST | 12346 | Jones | Peter | Davies | Bob | Richards | Craig |

Move row from one table to another?

I have two tables with the same column definitions. I need to move (not copy) a row from one table to another. Before I go off and use INSERT INTO/DELETE (in a transaction), is there a smarter way?
SQL Server 2005
for SQL Server 2005 and up, try the OUTPUT Clause (Transact-SQL) clause:
DELETE OldTable
OUTPUT DELETED.col1, DELETED.col2...
INTO NewTable
WHERE ID=...
Working example:
DECLARE #OldTable table(col1 int, col2 varchar(5), col3 char(5), col4 datetime)
DECLARE #NewTable table(col1 int, column2 varchar(5), col3 int , col_date char(23), extravalue int, othervalue varchar(5))
INSERT #OldTable VALUES (1 , 'AAA' ,'A' ,'1/1/2010' )
INSERT #OldTable VALUES (2 , 'BBB' ,'12' ,'2010-02-02 10:11:22')
INSERT #OldTable VALUES (3 , 'CCC' ,null ,null )
INSERT #OldTable VALUES (4 , 'B' ,'bb' ,'2010-03-02' )
DELETE #OldTable
OUTPUT DELETED.col1
,DELETED.col2
,CASE
WHEN ISNUMERIC(DELETED.col3)=1 THEN DELETED.col3
ELSE NULL END
,DELETED.col4
,CONVERT(varchar(5),DELETED.col1)+'!!'
INTO #NewTable (col1, column2, col3, col_date, othervalue)
OUTPUT 'Rows Deleted: ', DELETED.* --this line returns a result set shown in the OUTPUT below
WHERE col1 IN (2,4)
SELECT * FROM #NewTable
OUTPUT:
col1 col2 col3 col4
-------------- ----------- ----- ----- -----------------------
Rows Deleted: 2 BBB 12 2010-02-02 10:11:22.000
Rows Deleted: 4 B bb 2010-03-02 00:00:00.000
(2 row(s) affected)
col1 column2 col3 col_date extravalue othervalue
----------- ------- ----------- ----------------------- ----------- ----------
2 BBB 12 Feb 2 2010 10:11AM NULL 2!!
4 B NULL Mar 2 2010 12:00AM NULL 4!!
(2 row(s) affected)
You can try Insert into abc (a,b,c)
select(a,b,c) from def
doing above so will insert column a, b,c of def into column a,b,c of abc. after inserting run a delete table, drop table or truncate whatever is your criteria.
sample is:
Begin
Begin try
Begin Transaction
Insert into emp(name, department, salary)
Select empName,empDepartment,empSal from employees
Where employees.empID = 211
Truncate table employees
End Transaction
End try
Begin Catch
if ##Error > 0
Rollback Transaction
End Catch
End
There is no such thing as a MOVE command in SQL.
You'll have to first insert from table 1 to table 2
Then remove the copy from table 1.
No, you are pretty much stuck with insert and delete wrapped inside a transaction
INSERT dbo.newtable(
name,
department,
Salary
) SELECT
name,
FirstName,
Lastname
FROM (
DELETE dbo.oldtable
OUTPUT
DELETED.name,
DELETED.department,
DELETED.Salary
WHERE ID IN ( 1001, 1003, 1005 )
) AS RowsToMove
SELECT * FROM dbo.newtable
SELECT * FROM dbo.oldtable

Resources