Pivot rows to columns - sql

I need to create one master table to present in reporting services, but i have an issue on how to combine the data.
To be more specific, i have one table named "Reservaciones" which store information from residences that have been reserved in certain dates.
Now for example, I´m grouping the information by this fields:
R.ClaTrab AS WorkerId
R.ClaUbicacion AS UbicationID
R.ClaEstancia AS ResidenceID
R.FechaIni AS InitialDay
R.FechaFin AS LastDay
And the result is First result**
As you see in the picture we have two rows duplicated, the number four and number five to be exact.
So far this is my code
SELECT
R.ClaTrab AS WorkerId,
MAX(E.NomEstancia) AS ResidenceName,
R.ClaUbicacion AS UbicationID,
R.ClaEstancia AS ResidenceID,
DATEDIFF(DAY, R.FechaIni, R.FechaFin) AS NumberDays,
R.FechaIni AS InitialDay,
R.FechaFin AS LastDay
FROM Reservaciones AS R
INNER JOIN Estancias AS E ON E.ClaEstancia = R.ClaEstancia
WHERE E.ClaUbicacionEst = 3
GROUP BY R.ClaTrab,R.ClaUbicacion, R.ClaEstancia, R.FechaIni, R.FechaFin
ORDER BY R.FechaIni
I Want the result to be like this desire result, but i dont know how to do it, i have tried PIVOT but i cant get the result i want it.
If u need more information please, ask me.
thank you very much.
SOLUTION:
What i did is use the ROW NUMBER() and OVER PARTITION BY to create a group of workers in the same residence, then PIVOT the result in new columns.
SNIPPET
SELECT * FROM(
SELECT
MAX(E.NomEstancia) AS ResidenceName,
R.FechaIni AS InitialDay,
R.FechaFin AS LastDay,
DATEDIFF(DAY, R.FechaIni, R.FechaFin) AS NumberDays,
T.NomTrab AS Worker,
R.ClaUbicacion AS UbicationID,
R.ClaEstancia AS ResidenceID,
ROW_NUMBER() OVER(PARTITION BY FechaIni,FechaFin, R.ClaUbicacion, R.ClaEstancia ORDER BY T.NomTrab) AS GUEST
FROM Reservaciones AS R
INNER JOIN Estancias AS E ON E.ClaEstancia = R.ClaEstancia
INNER JOIN Trabajadores AS T ON T.ClaTrab = R.ClaTrab
WHERE E.ClaUbicacionEst = 3
GROUP BY T.NomTrab, R.ClaUbicacion, R.ClaEstancia, R.FechaIni,R.FechaFin) AS ONE
PIVOT( MAX(Worker) FOR GUEST IN ([1],[2],[3])) AS pvt
In the new query I added a new join to obtain the name of the workers

Since there can only be 2 workers, you can use Min and Max.
with cte as(
SELECT
R.ClaTrab AS WorkerId,
MAX(E.NomEstancia) AS ResidenceName,
R.ClaUbicacion AS UbicationID,
R.ClaEstancia AS ResidenceID,
DATEDIFF(DAY, R.FechaIni, R.FechaFin) AS NumberDays,
R.FechaIni AS InitialDay,
R.FechaFin AS LastDay
FROM
Reservaciones AS R
INNER JOIN
Estancias AS E
ON E.ClaEstancia = R.ClaEstancia
WHERE
E.ClaUbicacionEst = 3
GROUP BY
R.ClaTrab,
R.ClaUbicacion,
R.ClaEstancia,
R.FechaIni,
R.FechaFin),
cte2 as(
select
ResidenceName
,UbicationID
,ResidenceID
,NumberDays
,InitalDay
,LastDay
,Worker1 = max(WorkerId)
,Worker2 = min(WorkerId)
from
cte
group by
ResidenceName
,UbicationID
,ResidenceID
,NumberDays
,InitalDay
,LastDay)
select
ResidenceName
,UbicationID
,ResidenceID
,NumberDays
,InitalDay
,LastDay
,Worker1
,Worker2 = case when Worker1 = Worker2 then NULL else Worker2 end
from
cte2
ONLINE DEMO WITH PARTIAL TEST DATA

Related

SQL - Get the sum of several groups of records

DESIRED RESULT
Get the hours SUM of all [Hours] including only a single result from each [DevelopmentID] where [Revision] is highest value
e.g SUM 1, 2, 3, 5, 6 (Result should be 22.00)
I'm stuck trying to get the appropriate grouping.
DECLARE #CompanyID INT = 1
SELECT
SUM([s].[Hours]) AS [Hours]
FROM
[dbo].[tblDev] [d] WITH (NOLOCK)
JOIN
[dbo].[tblSpec] [s] WITH (NOLOCK) ON [d].[DevID] = [s].[DevID]
WHERE
[s].[Revision] = (
SELECT MAX([s2].[Revision]) FROM [tblSpec] [s2]
)
GROUP BY
[s].[Hours]
use row_number() to identify the latest revision
SELECT SUM([Hours])
FROM (
SELECT *, R = ROW_NUMBER() OVER (PARTITION BY d.DevID
ORDER BY s.Revision)
FROM [dbo].[tblDev] d
JOIN [dbo].[tblSpec] s
ON d.[DevID] = s.[DevID]
) d
WHERE R = 1
If you want one row per DevId, then that should be in the GROUP BY (and presumably in the SELECT as well):
SELECT s.DevId, SUM(s.Hours) as hours
FROM [dbo].[tblDev] d JOIN
[dbo].[tblSpec] s
ON [d].[DevID] = [s].[DevID]
WHERE s.Revision = (SELECT MAX(s2.Revision) FROM tblSpec s2)
GROUP BY s.DevId;
Also, don't use WITH NOLOCK unless you really know what you are doing -- and I'm guessing you do not. It is basically a license that says: "You can get me data even if it is not 100% accurate."
I would also dispense with all the square braces. They just make the query harder to write and to read.

Getting value from MAX(Date) Row in SQL Server

I am trying to get the last supplier of an item, by using the MAX function. What I am trying to achieve is showing what the supplier name was for the row with the MAX(Date) for all the stock items (shown below as account links).
The code I am using bring up multiple dates for the same accountlink, and I am struggling to see why. My code is:
SELECT
MAX(TxDate) AS Date,
ST.AccountLink,
V.Account AS Supplier
FROM _bvSTTransactionsFull AS ST
JOIN Vendor V on ST.DrCrAccount = V.DCLink
WHERE Module = 'AP'
AND Id = 'OGrv'
GROUP BY ST.AccountLink, V.Account
ORDER BY AccountLink
But my results look like the below
Try this out
select AccountLink,Supplier,date from(SELECT
ST.AccountLink,
V.Account AS Supplier,
TxDate as [date],
row_number()over(partition by ST.AccountLink order by TxDate desc)rownum
FROM _bvSTTransactionsFull AS ST
JOIN Vendor V on ST.DrCrAccount = V.DCLink
WHERE Module = 'AP'
AND Id = 'OGrv')t
where t.rownum = 1
The group by has been removed and ranking function is used to achieve the output
You need a simple subquery to select the last supplier.
select X.supplier as LastSupplier, X.Date as lastDate, X.AccountLink
from _bvSTTransactionsFull X
where X.Date = (select max(date)
from _bvSTTransactionsFull Y
where Y.AccountLink=X.AccountLink)
The subquery extracts the last date for any accountLink, so you can use it on the outer where condition.

Get the group by on 2 column and date as latest

I have 2 table and I m fetching record as below
The query is as
Select BMC.JCRS_Mem_crs_Code,
BMC.JCRS_Mem_Description,
BMC.JCRS_Mem_Date,
BJCM.JCRS_Mast_Title
From Bus_MemberCourse BMC
Inner Join Bus_JourneymanCourseMaster BJCM
On BMC.JCRS_Mem_crs_Code = BJCM.JCRS_Mast_Code
Where BMC.JCRS_Mem_Completed = 1
And BMC.JCRS_Mem_mem_ID = 5010
Group By BMC.JCRS_Mem_crs_Code,
BMC.JCRS_Mem_Description,
BMC.JCRS_Mem_Date,
BJCM.JCRS_Mast_Title
But what I want is I need to make group by on Jcrs_mem_crs_code and Jcrs_mem_description and if this 2 column data are common then I want to took the latest date only from this multiple dates. i.e. I want to pick only that row and ignore the other rows.
You just want MAX(date):
Select BMC.JCRS_Mem_crs_Code,
BMC.JCRS_Mem_Description,
MAX(BMC.JCRS_Mem_Date) as JCRS_Mem_Date,
BJCM.JCRS_Mast_Title
From Bus_MemberCourse BMC
Inner Join Bus_JourneymanCourseMaster BJCM
On BMC.JCRS_Mem_crs_Code = BJCM.JCRS_Mast_Code
Where BMC.JCRS_Mem_Completed = 1
And BMC.JCRS_Mem_mem_ID = 5010
Group By BMC.JCRS_Mem_crs_Code,
BMC.JCRS_Mem_Description,
BJCM.JCRS_Mast_Title
You don't need a Group by at all (you aren't doing any aggregation in your query).
This can easily be done with a Row_Number() windowed function with a Partition on those two columns whilst ordering by the date:
;With Cte As
(
Select BMC.JCRS_Mem_crs_Code,
BMC.JCRS_Mem_Description,
BMC.JCRS_Mem_Date,
BJCM.JCRS_Mast_Title,
Row_Number() Over (Partition By BMC.JCRS_Mem_crs_Code,
BMC.JCRS_Mem_Description
Order By BMC.JCRS_Mem_Date Desc) As RN
From Bus_MemberCourse BMC
Inner Join Bus_JourneymanCourseMaster BJCM
On BMC.JCRS_Mem_crs_Code = BJCM.JCRS_Mast_Code
Where BMC.JCRS_Mem_Completed = 1
And BMC.JCRS_Mem_mem_ID = 5010
)
Select JCRS_Mem_crs_Code,
JCRS_Mem_Description,
JCRS_Mem_Date,
JCRS_Mast_Title
From Cte
Where RN = 1

Select all rows with max date for each ID

I have the following query returning the data as shown below. But I need to exclude the rows with MODIFIEDDATETIME shown in red as they have a lower time stamp by COMMITRECID. As depicted in the data, there may be multiple rows with the max time stamp by COMMITRECID.
SELECT REQCOMMIT.COMMITSTATUS, NOTEHISTORY.NOTE, NOTEHISTORY.MODIFIEDDATETIME, NOTEHISTORY.COMMITRECID
FROM REQCOMMIT INNER JOIN NOTEHISTORY ON REQCOMMIT.RECID = NOTEHISTORY.COMMITRECID
WHERE REQCOMMIT.PORECID = 1234
Here is the result of the above query
The desired result is only 8 rows with 5 in Green and 3 in Black (6 in Red should get eliminated).
Thank you very much for your help :)
Use RANK:
WITH CTE AS
(
SELECT R.COMMITSTATUS,
N.NOTE,
N.MODIFIEDDATETIME,
N.COMMITRECID,
RN = RANK() OVER(PARTITION BY N.COMMITRECID ORDER BY N.MODIFIEDDATETIME)
FROM REQCOMMIT R
INNER JOIN NOTEHISTORY N
ON R.RECID = N.COMMITRECID
WHERE R.PORECID = 1234
)
SELECT *
FROM CTE
WHERE RN = 1;
As an aside, please try to use tabla aliases instead of the whole table name in your queries.
*Disclaimer: You said that you wanted the max date, but the selected values in your post were those with the min date, so I used that criteria in my answer
This method just limits your history table to those with the MINdate as you described.
SELECT
REQCOMMIT.COMMITSTATUS,
NOTEHISTORY.NOTE,
NOTEHISTORY.MODIFIEDDATETIME,
NOTEHISTORY.COMMITRECID
FROM REQCOMMIT
INNER JOIN NOTEHISTORY ON REQCOMMIT.RECID = NOTEHISTORY.COMMITRECID
INNER JOIN (SELECT COMMITRECID, MIN(MODIFIEDDATETIME) DT FROM NOTEHISTORY GROUP BY COMMITRECID) a on a.COMMITRECID = NOTEHISTORY.COMMITRECID and a.DT = NOTEHISTORY.MODIFIEDDATETIME
WHERE REQCOMMIT.PORECID = 1234

Postgres: Making column in first row contain sum of same column in other rows

I'm a newbie in postgres and i have a troubling issue.
Suppose the output of my SQL query is
123456789;"2014-11-20 12:30:35.454875";500;200;"2014-11-16 16:16:26.976258";300
123456789;"2014-11-20 12:30:35.454875";500;200;"2014-11-16 16:16:27.173523";100
What i want is to sum up all the 4th column, and so that the first row will contain the sum of the 4th column
123456789;"2014-11-20 12:30:35.454875";500;400;"2014-11-16 16:16:26.976258";300
My query is
select l.phone_no, l.loan_time, l.cents_loaned/100, r.cents_deducted/100, r.event_time,
r.cents_balance/100
from tbl_table1 l
LEFT JOIN tbl_table2 r
ON l.tb1_id = r.tbl2_id
where l.phone_no=123456789
order by r.event_time desc
Any help will be appreciated.
Maybe this helps. It will add a new row containing the sum of the 4th column.
WITH query AS (
SELECT l.phone_no, l.loan_time, l.cents_loaned/100 AS cents_loaned,
r.cents_deducted/100 AS cents_deducted, r.event_time,
r.cents_balance/100 AS cents_balance,
ROW_NUMBER() OVER (ORDER BY r.event_time DESC) rn,
SUM(cents_deducted/100) OVER () AS sum_cents_deducted
FROM tbl_table1 l
LEFT
JOIN tbl_table2 r
ON l.tb1_id = r.tbl2_id
WHERE l.phone_no=123456789
)
SELECT phone_no, loan_time, cents_loaned, cents_deducted, event_time, cents_balance
FROM query
WHERE rn > 1
UNION
ALL
SELECT phone_no, loan_time, cents_loaned, sum_cents_deducted, event_time, cents_balance
FROM query
WHERE rn = 1
Use a window function over the whole set (OVER ()) as frame:
select l.phone_no, l.loan_time, l.cents_loaned/100
, sum(r.cents_deducted) OVER () / 100 AS total_cents_deducted
, r.event_time, r.cents_balance/100
FROM tbl_table1 l
LEFT JOIN tbl_table2 r ON l.tb1_id = r.tbl2_id
WHERE l.phone_no = 123456789
ORDER BY r.event_time desc
This will return all rows, not just the first. Your question is unclear as to that.