SQL Server Merge 2 rows into 1 - sql

Is it possible to merge 2 rows into a single row in SSRS 2008?
Each part will have a record for each site
+---------------+-------+-------+
|Part Number |Cost |Site |
+---------------+-------+-------+
|1 |2.4 |Site 1 |
|1 |68.8 |Site 2 |
+---------------+-------+-------+
Desired Result
+-----------+-------+-------+
|Part Number|Site 1 |Site 2 |
+-----------+-------+-------+
| 1 |2.4 |68.8 |
+-----------+-------+-------+
Thank you

If you know your site numbers/names will not change dynamically then can use CASE WHEN:s
SELECT PartNumber,
MAX(CASE WHEN Site=1 THEN Cost ELSE NULL END) AS Site1_Cost,
MAX(CASE WHEN Site=2 THEN Cost ELSE NULL END) AS Site2_Cost
FROM Parts
GROUP BY PartNumber
By grouping we eliminated a NULL values...
Here link with SQL Fiddle example

In SSRS to you need to use MATRIX report to convert rows into columns without using PIVOT operator
Suppose you have a table SSRSPivot
Create table SSRSPivot
(PartNumber int ,Cost decimal(18,2),Site varchar(max))
Insert into SSRSPivot
values
(1,2.4,'Site 1'),
(1,68.8,'Site 2' )
The data is in the below format
+---------------+-------+-------+
|PartNumber |Cost |Site |
+---------------+-------+-------+
|1 |2.4 |Site 1 |
|1 |68.8 |Site 2 |
+---------------+-------+-------+
Create a new blank report and name it as PIVOT.Create a datasource and in the dataset write the query
Select PartNumber ,Cost,Site from SSRSPivot
Drag a matrix from the toolbox onto the SSRS designer.For Rows select PartNumber .For columns select Site and for the data select Sum(Cost)
When you do the above step ,you will get the row and column details like the one below
Final Result will look like

This type of data transformation is known as a PIVOT. Starting in SQL Server 2005, there is a function that can transpose the data into columns for you.
If you have a known number of Site values that you want to turn into columns, then you can hard-code the query:
select part_number, [Site 1], [Site 2]
from
(
select part_number, cost, site
from yourtable
) src
pivot
(
sum(cost)
for site in ([Site 1], [Site 2])
) piv;
See SQL Fiddle with Demo
But if you have an unknown number of values, then you will need to use dynamic SQL to generate the column list to be used in the query:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(site)
from yourtable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT part_number,' + #cols + '
from
(
select part_number, cost, site
from yourtable
) x
pivot
(
sum(cost)
for site in (' + #cols + ')
) p '
execute(#query)
See SQL Fiddle with Demo. Both will give the result:
| PART_NUMBER | SITE 1 | SITE 2 |
---------------------------------
| 1 | 2.4 | 68.8 |

Related

How do I move values from a single column into individual fields with a query

I currently have a table of information that looks something like this:
ACCTS | YEAR | FEE
-------------------------
MBR2056 | 2002 | 25.00
MBR2058 | 2002 | 12.00
MBR2060 | 2002 | 15.00
MBR2056 | 2003 | 25.00
MBR2060 | 2003 | 10.00
And I am trying to break the information out of column 2 (with each year as the header), with fields broken out for each value in the "FEE" column, by year. What I am seeking is something that will look like this:
ACCTS | 2002 | 2003
-------------------------
MBR2056 | 25.00 | 25.00
MBR2058 | 12.00 |
MBR2060 | 15.00 | 10.00
A big part of my problem is that the numbers in the ACCTS column are not sequential, but they are ascending in order. I can group my query by the ACCTS field, but can only collect the data one year at a time. I would really like to break out the FEES values into YEAR columns, and I'm not having much luck. Anyone who can help will be gladly appreciated. Thanks in advance
Simple pivot will get this results as below:
Select * from YourTable
pivot (sum(Fee) for [Year] in ([2002],[2003])) p
If you have other columns in that table then
Select * from
(Select Accts, [Year], Fee from YourTable ) a
pivot (sum(Fee) for [Year] in ([2002],[2003])) p
using conditional aggregation to pivot your data:
select
ACCTS
, [2002] = max(case when [year] = 2002 then fee end)
, [2003] = max(case when [year] = 2003 then fee end)
from tbl
group by ACCTS
I used max() to imply that it was a single source value for fee. If you had multiple fee per accts and year then I would have used sum().
Just to expand on Kannan Kandasamy's answer
If you wish, you can calculate the columns dynamically, either by querying and then building the SQL in VB or by constructing the SQL directly in your query, I implemented this as a stored procedure
CREATE PROCEDURE GetFees AS
BEGIN
declare #columns nvarchar(max)
select #columns = coalesce(#columns + ', ', '')+
'['+cast(year as varchar(4))+']'
from (select distinct(year) as year from mytable) x;
set #columns = 'select * from mytable pivot (sum(fee) for year in ('+
#columns + ')) x'
exec dbo.sp_executesql #columns
END
You can then just call the stored procedure dbo.GetFees from your VB code to get the data.
Please note that you have to be certain about the contents of your columns, as this could lead to SQL injection. You should be fine if the year column is an int.

Expression in FOR section of PIVOT

I'm trying to use PIVOT to get the total weight of purchases per product, broken down by year/month in columns. Something like this:
+------------+--------+--------+--------+
| ProductKey | Jan-14 | Feb-14 | Mar-14 | Etc...
+------------+--------+--------+--------+
| 10 | 5000 | 7000 | 3000 |
| 20 | 10000 | 8000 | 6000 |
| 30 | 250 | 500 | 400 |
+------------+--------+--------+--------+
This is my first time trying to use PIVOT, so not sure this is right:
PIVOT
(
SUM([PO_PurchaseOrderLines].[EstimatedWeight])
FOR
LEFT(DATENAME(MONTH,[PO_Date]),3) & "-" & RIGHT(YEAR([PO_Date]),2)
IN (Jan-14, Feb-14, Mar-14, Apr-14, May-14, Jun-14, Jul-14, Aug-14, Sep-14, Oct-14, Nov-14, Dec-14, Jan-15, Feb-15, Mar-15, Apr-15, May-15, Jun-15, Jul-15, Aug-15, Sep-15, Oct-15, Nov-15, Dec-15, Jan-16, Feb-16, Mar-16, Apr-16, May-16, Jun-16, Jul-16, Aug-16, Sep-16, Oct-16, Nov-16, Dec-16, Jan-17, Feb-17, Mar-17)
) AS POPivot
Running this results in:
[Microsoft][ODBC SQL Server Driver][SQL Server]Incorrect syntax near the keyword 'LEFT'.
Is using an expression like this in the FOR section not possible? Is there something else incorrect?
Select *
From (
Select ProductKey
,Col = format(PO_Date,'MMM-yy')
,EstimatedWeight
From YourTable A
) A
Pivot (sum(EstimatedWeight) For [Col] in ([Jan-14],[Feb-14],[Mar-14]) ) p
You can't use an expression in the FOR section, it needs to be a column in the query you're trying to pivot. I recommend performing that operation and assigning the value to a column in your initial query and then referencing that column under FOR.
This is the Requested Dynamic Version
Declare #SQL varchar(max) = ''
Select #SQL = Stuff((Select ',' + QuoteName(Col)
From (Select Distinct Top 100
Col=format(PO_Date,'MMM-yy')
,Ord=format(PO_Date,'yyyy-MM')
From YourTable
Where PO_Date>=DateAdd(MONTH,-36,DateFromParts(Year(GetDate()),Month(GetDate()),1)) -- Adjust This Value +/-
Order By 2
) A For XML Path('')),1,1,'')
Select #SQL = '
Select *
From (
Select ProductKey
,Col = format(PO_Date,''MMM-yy'')
,EstimatedWeight
From YourTable A
) A
Pivot (sum(EstimatedWeight) For [Col] in (' + #SQL + ') ) p'
Exec(#SQL);

SQL Server: UPDATE after pivot (unpivot needed?)

Two days ago I asked how to use pivot in SQL to transpose a table.
With your help I got it right, here the solution: SQL server: Transpose Rows to Columns (n:m relationship)
I'm running SQL Server 2012, with an OBDC-connection, programming in C#.
So now I have:
| mitID | Name | FamName | DOB | abtIDref | HV | PEV | Drive | Nex |
|-------|--------|---------|------------|----------|---------------|------------|------------|------------|
| 1 | Frank | Sinatra | 12.12.1915 | 1 | **30.5.2016** | | 05.06.2015 | 02.11.2015 |
| 2 | Robert | Downey | 4.4.1965 | 2 | 27.7.2014 | 01.01.2016 | 20.01.2015 | |
I get this with following SQL statement:
DECLARE #sql AS NVARCHAR(MAX)
DECLARE #cols AS NVARCHAR(MAX)
SELECT #cols = ISNULL(#cols + ',', '') + QUOTENAME(Descr)
FROM Faehigkeiten ORDER BY faeID
SET #sql = N'
SELECT mitID, Name, FamName, DOB, abtIDref, ' + #cols + '
FROM(
SELECT mitID, Name, FamName, DOB, abtIDref, [when], descr
FROM Mitarbeiter m
JOIN[Link - List] l ON m.mitID = l.mitIDref
JOIN Faehigkeiten f ON f.faeID = l.feaIDref
) a
PIVOT(MAX([when]) FOR descr IN(' + #cols + ')) p'
EXEC sp_executesql #sql
But when I enter a new date (shown in asterisk above), or change a name of a member, how do I save the data?
I thought about unpivot, but I have no idea how to use it in my case.
My solution would be to loop through all the rows and compare it to existing entries ... but that could take a long time with lots of members.
Can you point me in some direction, wether it is possible to UPDATE this an easy way? I only need UPDATE no INSERT since new rows are forbidden.
Right now I have no class for my members. I load my DataGridView in C# with the following code:
BindingSource bsMember = new BindingSource();
bsMember.DataSource = DBMember.Get();
dgv.DataSource = bsMember;
The DBMember.Get() returns a DataTable made with the above shown SQL code.
Sorry, I have no approach except my loop through each row :/
EDIT: The provided duplicate is hard for me to follow because of the JOIN in my SQL-code. Can i JOIN while updating?
Please consider helping me directly.

SQL concat rows with same name value

Let say I got table like that
Name | Stage | Date
-------------------
A | 1st | 03092014
A | 2nd | 04092014
A | 3rd | 05092014
B | 1st | 06092014
B | 2nd | 08092014
C | 1st | 03092014
I wonder how to write SQL code wich would concat rows with same names and I will get something like that
Name | Stage | Date
----------------------+-----------------------------
A | 1st , 2nd, 3rd | 03092014 04092014 05092014
B | 1st, 2nd | 06092014 08092014
C | 1st | 03092014
Do I need to run through table with for cycle or is there better way to do that?
UPD:
I found out that I need to use this queries in Excel
You can use GROUP_CONCAT for this:
SELECT Name
, GROUP_CONCAT(Stage) AS Stages
, GROUP_CONCAT(Date) AS Dates
FROM my_table
GROUP BY Name;
With respect to your question - I am assuming you are using MS SQL Server 2008 or higher to get he desired output
I would suggest to use CROSS APPLY here to concat the data -
Assumed Your Table name - temptable
SELECT distinct tblMain.Name, substring(stages, 1, len(stages)-1) as [Stage],substring(dates, 1, len(dates)-1) as [Date]
FROM temptable tblMain
CROSS APPLY (
SELECT LTRIM(RTRIM(Stage)) + ','
FROM temptable tblDup1 WITH(NOLOCK)
WHERE tblDup1.Name= tblMain.Name
FOR XML PATH('')
) t1 (stages)
CROSS APPLY (
SELECT LTRIM(RTRIM(Date)) + ' '
FROM temptable tblDup2 WITH(NOLOCK)
WHERE tblDup2.Name= tblMain.Name
FOR XML PATH('')
) t2 (dates)
Working FIDDLE OUTPUT

SQL Server 2005 Pivot on Unknown Number of Columns

I am working with a set of data that looks something like the following.
StudentName | AssignmentName | Grade
---------------------------------------
StudentA | Assignment 1 | 100
StudentA | Assignment 2 | 80
StudentA | Total | 180
StudentB | Assignment 1 | 100
StudentB | Assignment 2 | 80
StudentB | Assignment 3 | 100
StudentB | Total | 280
The name and number of assignments are dynamic, I need to get results simlilar to the following.
Student | Assignment 1 | Assignment 2 | Assignment 3 | Total
--------------------------------------------------------------------
Student A | 100 | 80 | null | 180
Student B | 100 | 80 | 100 | 280
Now ideally I would like to sort the column based on a "due date" that could be included/associated with each assignment. The total should be at the end if possible (It can be calculated and removed from the query if possible.)
I know how to do it for the 3 assignments using pivot with simply naming the columns, it is trying to do it in a dynamic fashion that I haven't found a GOOD solution for yet. I am trying to do this on SQL Server 2005
EDIT
Ideally I would like to implement this WITHOUT using Dynamic SQL, as that is against the policy. If it isn't possible...then a working example with Dynamic SQL will work.
I know you said no dynamic SQL, but I don't see any way to do it in straight SQL.
If you check out my answers to similar problems at Pivot Table and Concatenate Columns and PIVOT in sql 2005
The dynamic SQL there is not vulnerable to injection, and there is no good reason to prohibit it. Another possibility (if the data is changing very infrequently) is to do code-generation - instead of dynamic SQL, the SQL is generated to a stored procedure on a regular basis.
To PIVOT this data using dynamic sql you can use the following code in SQL Server 2005+:
Create Table:
CREATE TABLE yourtable
([StudentName] varchar(8), [AssignmentName] varchar(12), [Grade] int)
;
INSERT INTO yourtable
([StudentName], [AssignmentName], [Grade])
VALUES
('StudentA', 'Assignment 1', 100),
('StudentA', 'Assignment 2', 80),
('StudentA', 'Total', 180),
('StudentB', 'Assignment 1', 100),
('StudentB', 'Assignment 2', 80),
('StudentB', 'Assignment 3', 100),
('StudentB', 'Total', 280)
;
Dynamic PIVOT:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(AssignmentName)
from yourtable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT StudentName, ' + #cols + ' from
(
select StudentName, AssignmentName, grade
from yourtable
) x
pivot
(
min(grade)
for assignmentname in (' + #cols + ')
) p '
execute(#query)
See SQL Fiddle with Demo
The result is:
| STUDENTNAME | ASSIGNMENT 1 | ASSIGNMENT 2 | ASSIGNMENT 3 | TOTAL |
--------------------------------------------------------------------
| StudentA | 100 | 80 | (null) | 180 |
| StudentB | 100 | 80 | 100 | 280 |
The only way I've found to do this is to use dynamic SQL and put the column labels into a variable.
you could query information_schema to get the column names and types, then use the result as a subquery when you build your result set. Note you'll likely have to change the login's access a bit.
This is the same as PIVOT in sql 2005
If this data is for consumption in a report you could use a SSRS matrix. It will generate columns dynamically from result set. I've used it many times - it works quite well for dynamic crosstab reports.
Here's a good example w/ dynamic sql.
http://www.simple-talk.com/community/blogs/andras/archive/2007/09/14/37265.aspx
SELECT TrnType
INTO #Temp1
FROM
(
SELECT '[' + CAST(TransactionType AS VARCHAR(4)) + ']' AS TrnType FROM tblPaymentTransactionTypes
) AS tbl1
SELECT * FROM #Temp1
SELECT * FROM
(
SELECT FirstName + ' ' + LastName AS Patient, TransactionType, ISNULL(PostedAmount, 0) AS PostedAmount
FROM tblPaymentTransactions
INNER JOIN emr_PatientDetails ON tblPaymentTransactions.PracticeID = emr_PatientDetails.PracticeId
INNER JOIN tblPaymentTransactionDetails ON emr_PatientDetails.PatientId = tblPaymentTransactionDetails.PatientID
AND tblPaymentTransactions.TransactionID = tblPaymentTransactionDetails.TransactionID
WHERE emr_PatientDetails.PracticeID = 152
) tbl
PIVOT (SUM(PostedAmount) FOR [TransactionType] IN (SELECT * FROM #Temp1)
) AS tbl4
select studentname,[Assign1],[Assign2],[Assign3],[Total]
from
(
select studentname, assignname, grade from student
)s
pivot(sum(Grade) for assignname IN([Assign1],[Assign2],[Assign3],[Total])) as pvt