Place Data from Same Column in Different Columns in Resultset - sql-server

I have a request I wasn't sure to handle. I was thinking of using PIVOT, but I wasn't sure if that would be the way to go.
I have the following Data:
EmployeeA, DepartmentB, 1/10/2010
EmployeeA, DepartmentA, 1/1/2000
EmployeeB, DepartmentC, 1/3/2011
They want output for only the employees that have been in different departments. Something that looks like this (order is important due to the dates):
EmployeeA, DepartmentA, DepartmentB
Any help is appreciated. For some reason, my mind isn't finding a good solution.

You can do this by doing a self JOIN on the table and then using a PIVOT to get the data in the format that you want:
SELECT *
FROM
(
SELECT t1.emp, t1.dept, t1.dt
FROM test t1
INNER JOIN test t2
ON t1.emp = t2.emp
AND t1.dept != t2.dept
) x
PIVOT
(
min(dt)
for dept in ([A], [B], [C], [D], [E])
) p
See SQL Fiddle with Demo
If you remove the JOIN you will get all records, but you stated you only want the records that have been in more than one department.

Here's the answer I got which I got largely based on your work. Pivot doesn't work because I don't know the categories (in this case Department) ahead of time and I can only have two of them.
Maybe there's an easier way. I didn't use a CTE, because I believe this should work for Sybase as well which I don't think supports that.
select Meta1.[Employee ID],
Meta1.Department as PreviousDepartment,
Meta2.Department as CurrentDepartment
from
(
SELECT t1.[First Name], t1.[Last Name],
t1.[Employee ID], t1.Department, t1.[Hire Date],
ROW_NUMBER() over(PARTITION by t1.[EMPLOYEE ID] order by t1.[Hire Date]) as RowNum
FROM EMPLOYEE t1
INNER JOIN EMPLOYEE t2
ON t1.[Employee ID] = t2.[Employee ID]
AND t1.Department != t2.Department
) Meta1
inner join
(
SELECT t1.[Employee ID], t1.Department, t1.[Hire Date],
ROW_NUMBER() over(PARTITION by t1.[EMPLOYEE ID] order by t1.[Hire Date]) as RowNum
FROM EMPLOYEE t1
INNER JOIN EMPLOYEE t2
ON t1.[Employee ID] = t2.[Employee ID]
AND t1.Department != t2.Department
) Meta2
on Meta1.[Employee ID]=Meta2.[Employee ID]
where Meta1.RowNum=1
and Meta2.RowNum=2

Related

Is there any way to get data above a selected percentile?

I have a sp as following to get a list of areacode(phone) and sales amount on a selected percentile. For example at 0.5. However, I don't only want to see the data at 0.5,I also want to see the data above 0.5(the selected parameter).How can I do with sql server coding?
CREATE PROCEDURE USP_Percentile1 #per real
AS
SELECT c.[area code],PERCENTILE_DISC(#per) WITHIN GROUP (ORDER BY SalesAmount) OVER (PARTITION BY [area code]) AS percentileamount
from (select SUBSTRING(s.phone,2,3) as [area code],sum(b.Salesamount) as SalesAmount from Orders a
join (select OrderID, sum(UnitPrice * Quantity * (1-Discount) ) as Salesamount from [Order Details] group by OrderID) as b
on a.OrderID = b.OrderID
join Shippers s
on a.ShipVia=s.ShipperID
group by s.Phone) c
exec SP_1 0.5
You can use the PERCENT_RANK function for this. Place it inside the subquery and filter it afterwards.
You should make good use of whitespace and formatting, it's free.
Also, see Bad Habits to Kick : Using table aliases like (a, b, c) or (t1, t2, t3)
CREATE PROCEDURE USP_Percentile1 #per real
AS
SELECT
o.[area code],
percentileamount
from (
select
SUBSTRING(s.phone, 2, 3) as [area code],
sum(od.Salesamount) as SalesAmount,
PERCENTILE_DISC(#per) WITHIN GROUP (ORDER BY sum(od.Salesamount)) OVER (PARTITION BY [area code]) AS percentileamount,
PERCENT_RANK() OVER (PARTITION BY [area code] ORDER BY sum(od.Salesamount)) AS percentile
from Orders o
join (
select
OrderID,
sum(UnitPrice * Quantity * (1-Discount) ) as Salesamount
from [Order Details]
group by OrderID
) as od on o.OrderID = od.OrderID
join Shippers s on o.ShipVia = s.ShipperID
group by s.Phone
) o
where
o.percentile >= #per;

SQL Server : restricting data range

The query below is supposed to show details for 2 types of products: DIS001 and DIS002.
When DIS002, this should "reset" the query, so that it only shows DIS001 products which were sold after that the date when DIS002 was sold.
To be honest, I'm not even sure if this is possible. I'll be grateful for any suggestions.
SELECT DISTINCT
Sales.RaisedDateTime AS [Date],
Contacts.ContactID AS [Contact ID],
Contacts.SiteID AS [Site ID],
Sales.ProductID AS [Product],
CASE
WHEN Sales.ProductID = 'DIS002'
THEN Sales.RaisedDate
ELSE CONVERT(DATETIME, CONVERT(VARCHAR(10), '2019-10-28', 101) + ' 00:00:00')
END AS [Start Date]
FROM
((Bookings.Bookings Bookings
INNER JOIN
Contacts.Contacts Contacts ON (Bookings.ContactID = Contacts.ContactID))
INNER JOIN
Sales.Sales Sales ON (Bookings.ContactID = Sales.ContactID))
WHERE
(Sales.ProductID = 'DIS001' AND
Sales.RaisedDate >= MAX([Start Date])
There are lots of different syntax's to solve this, but here is one:
;with DIS002 as (
select ContactID, max(RaisedDate) as DIS002Date
from Sales.Sales
where ProductID = 'DIS002'
group by ContactID
)
SELECT DISTINCT
Sales.RaisedDateTime AS [Date],
Contacts.ContactID AS [Contact ID],
Contacts.SiteID AS [Site ID],
Sales.ProductID AS [Product]
FROM
((Bookings.Bookings Bookings
INNER JOIN
Contacts.Contacts Contacts ON (Bookings.ContactID = Contacts.ContactID))
INNER JOIN
Sales.Sales Sales ON (Bookings.ContactID = Sales.ContactID))
LEFT JOIN
DIS002 on DIS002.ContactID = Sales.ContactID
WHERE
Sales.ProductID = 'DIS001' AND
Sales.RaisedDate >= isnull(DIS002date,'1900-01-01')

How to combine two rows into a single row in CTE

I am getting data in a CTE like this.
Here I am getting two records for each ActivityId, what I want to achieve is two create a single record from the two rows. From the row where r2=1 I need only the RDate as Todate, ActualProgress as endprogress and PlannedProgress as endplannedprogress because these are the only values that will changed on both the rows.
I am getting this data in a CTE.
WITH CTE as(SELECT row_number() over (partition by pmaph.ActivityId order by date) r1, row_number() over (partition by pmaph.ActivityId order by date desc) r2,pma.PlanEndDate as PlanEndDate ,pma.PlanStartDate as PlanStartDate,pmaph.ActivityId,pmaph.ProjectMilestoneActivProgHist_Id as ProMileAvtiID,umd.UOM_Name as UomName, pmm.MilestoneName as MilestoneName,pma.ActivityName as ActivityName ,pmp.ProjectName as ProjectName, Replace((rtrim(ltrim(Convert(varchar(12),Cast(pmaph.Date as Datetime),106)))),' ','-') as RDate, isnull(pmaph.Actual_Progress,0) as ActualProgress,isnull(pmaph.Planned_Progress,0) as PlannedProgress FROM ProjectMilestoneActivityProgressHistory as pmaph left join dbo.PM_Project as pmp on pmaph.ProjectId=pmp.ProjectId left join dbo.PM_Activity as pma on pmaph.ActivityId=pma.ActivityId left join dbo.PM_Milestone as pmm on pmaph.MilestoneId=pmm.MilestoneId left join dbo.UOMDetail as umd on pma.UOM_Id=umd.UOM_Id where pmaph.Client_Id=#ClientId
)
select * from CTE where r1=1 or r2=1
You can do a Group By ActivityId and including a MAX(RDate) AND MAX(ActualProgress), it should return you only one-row per ActivityId.
Maybe this can give you a hint. Make sure to keep the format of your SQL.
;WITH CTE as
(
SELECT
row_number() over (partition by pmaph.ActivityId order by date) r1,
row_number() over (partition by pmaph.ActivityId order by date desc) r2,
pma.PlanEndDate as PlanEndDate ,
pma.PlanStartDate as PlanStartDate,
pmaph.ActivityId,
pmaph.ProjectMilestoneActivProgHist_Id as ProMileAvtiID,
umd.UOM_Name as UomName,
pmm.MilestoneName as MilestoneName,
pma.ActivityName as ActivityName,
pmp.ProjectName as ProjectName,
Replace((rtrim(ltrim(Convert(varchar(12),Cast(pmaph.Date as Datetime),106)))),' ','-') as RDate,
isnull(pmaph.Actual_Progress,0) as ActualProgress,
isnull(pmaph.Planned_Progress,0) as PlannedProgress
FROM
ProjectMilestoneActivityProgressHistory as pmaph
left join dbo.PM_Project as pmp on pmaph.ProjectId=pmp.ProjectId
left join dbo.PM_Activity as pma on pmaph.ActivityId=pma.ActivityId
left join dbo.PM_Milestone as pmm on pmaph.MilestoneId=pmm.MilestoneId
left join dbo.UOMDetail as umd on pma.UOM_Id=umd.UOM_Id
where
pmaph.Client_Id=#ClientId
)
SELECT
C1.*, -- Now you have all data in one row (by Activity), select whichever columns you want
C2.*
FROM
CTE AS C1
INNER JOIN CTE AS C2 ON
C1.ActivityId = C2.ActivityId AND
C2.r2 = 1 -- ... and join against the other row
WHERE
C1.r1 = 1 -- pick 1 row by Activity

SQL Query to Find All distinct Duplicates across 2 columns

Sale ID Group ID
JED93B53QEJYST4102 01A42QEJAXT17A7
JED93B53QEJYST4102 01A42QEJAXT17A7
JED93B53QEJYST4102 01A42QEJAXT17A7
JED93B53QEJYST4102 01A42QEJAXT17A7
JED8754AQEJEHT4119 01C49QEJPJT133E
JED8754AQEJEHT4119 01C49QEJPJT133E
JED8754AQEJEHT4119 01C49QEJPJT133E
JEDA67C1QEJEQR4A4A 03D80QEJRSR1BC5
JEDA67C1QEJEQR4A4A 03D80QEJRSR1BC5
JED46D04QEJXOR468B 040E5QEJGQR174D
JED658D9QEJIOS4F38 053BDQEJNSS11D4
JED658D9QEJIOS4F38 053BDQEJNSS11D4
JED99C53QEJNMR4973 053BDQEJNSS11D4
JED658D9QEJIOS4F38 053BDQEJNSS11D4
JED658D9QEJIOS4F38 053BDQEJNSS11D4
JED457D4QEJFGR468F 0B829QEJHJR18F5
JED457D4QEJFGR468F 0B829QEJHJR18F5
JEDA98F8QEJCZQ4F6A 0B829QEJHJR18F5
I am stuck in a dilemma wherein I am trying to write a SQL Query that will give me only those records which has duplicate group IDs but with unique Sale IDs. My Expected Output is similar to below. Is there anyway to achieve this?
JED99C53QEJNMR4973 053BDQEJNSS11D4
JED658D9QEJIOS4F38 053BDQEJNSS11D4
JED457D4QEJFGR468F 0B829QEJHJR18F5
JEDA98F8QEJCZQ4F6A 0B829QEJHJR18F5
Any help appreciated. Thanks a lot.
EDIT: Using Group By I can achieve till this:
Sale ID Group ID
JED93B53QEJYST4102 01A42QEJAXT17A7
JED8754AQEJEHT4119 01C49QEJPJT133E
JEDA67C1QEJEQR4A4A 03D80QEJRSR1BC5
JED46D04QEJXOR468B 040E5QEJGQR174D
JED658D9QEJIOS4F38 053BDQEJNSS11D4
JED99C53QEJNMR4973 053BDQEJNSS11D4
JED457D4QEJFGR468F 0B829QEJHJR18F5
JEDA98F8QEJCZQ4F6A 0B829QEJHJR18F5
EDIT FINAL: Thanks for all the responses and the finally was able to sort this out the way I wanted it. I managed to learn something new. Apologies if my question was not clear. I required it precisely that way as the table has more than a 100,000 records and I need to audit those with different SaleID for a single GroupID. The below query by Giorgos Betsos worked
SELECT t1.[Sale ID], t1.[Group ID]
FROM mytable AS t1
JOIN (
SELECT [Group ID]
FROM mytable
GROUP BY [Group ID]
HAVING COUNT(*) > 1 AND COUNT(DISTINCT [Sale ID]) > 1
) AS t2 ON t1.[Group ID] = t2.[Group ID]
Group By t1.[Group ID], t1.[Sale ID]
It seems like the required GROUP ID values can be obtained by the following query:
SELECT [Group ID]
FROM mytable
GROUP BY [Group ID]
HAVING COUNT(*) > 1 AND COUNT(DISTINCT [Sale ID]) > 1
You can use the above query as a derived to table to join back to the original table so as to get the Sale ID value as well:
SELECT t1.[Sale ID], t1.[Group ID]
FROM mytable AS t1
JOIN (
SELECT [Group ID]
FROM mytable
GROUP BY [Group ID]
HAVING COUNT(*) > 1 AND COUNT(DISTINCT [Sale ID]) > 1
) AS t2 ON t1.[Group ID] = t2.[Group ID]
Try this,
DECLARE #Table TABLE (
[Sale ID] VARCHAR(100)
,[Group ID] VARCHAR(100)
)
insert into #Table values
('JED93B53QEJYST4102','01A42QEJAXT17A7')
,('JED93B53QEJYST4102','01A42QEJAXT17A7')
,('JED93B53QEJYST4102','01A42QEJAXT17A7')
,('JED93B53QEJYST4102','01A42QEJAXT17A7')
,('JED8754AQEJEHT4119','01C49QEJPJT133E')
,('JED8754AQEJEHT4119','01C49QEJPJT133E')
,('JED8754AQEJEHT4119','01C49QEJPJT133E')
,('JEDA67C1QEJEQR4A4A','03D80QEJRSR1BC5')
,('JEDA67C1QEJEQR4A4A','03D80QEJRSR1BC5')
,('JED46D04QEJXOR468B','040E5QEJGQR174D')
,('JED658D9QEJIOS4F38','053BDQEJNSS11D4')
,('JED658D9QEJIOS4F38','053BDQEJNSS11D4')
,('JED99C53QEJNMR4973','053BDQEJNSS11D4')
,('JED658D9QEJIOS4F38','053BDQEJNSS11D4')
,('JED658D9QEJIOS4F38','053BDQEJNSS11D4')
,('JED457D4QEJFGR468F','0B829QEJHJR18F5')
,('JED457D4QEJFGR468F','0B829QEJHJR18F5')
,('JEDA98F8QEJCZQ4F6A','0B829QEJHJR18F5')
SELECT DISTINCT t1.[Sale ID]
,t1.[Group ID]
FROM #Table AS t1
JOIN (
SELECT [Group ID]
FROM #Table
GROUP BY [Group ID]
HAVING COUNT(DISTINCT [Sale ID]) > 1
) AS t2 ON t1.[Group ID] = t2.[Group ID]
write a SQL Query that will give me only those records which has duplicate group IDs but with unique Sale IDs
Here is how to do this verbatim:
SELECT t1.[Sale ID],
t1.[Group ID]
FROM yourTable t1
INNER JOIN
(
SELECT [Group ID]
FROM yourTable
GROUP BY [Group ID]
HAVING COUNT(*) > 1 AND -- duplicate group IDs
COUNT(DISTINCT [Sale ID]) = COUNT(*) -- but all sale IDs unique
) t2
ON t1.[Group ID] = t2.[Group ID]
However, your desired output seemed to suggest something more simple:
SELECT DISTINCT [Sale ID], [Group ID]
FROM yourTable
or
SELECT [Sale ID], [Group ID]
FROM yourTable
GROUP BY [Sale ID], [Group ID]

Select Multiple Columns join SQL Server

I have an Employee table like this
And a second table for EmployeeComments with the EmployeeID as foreign key:
I would like to query the employees with their comments in the following format:
select Name, Comment
from Employee emp
left join EmployeeComments empC on empC.EmployeeID = emp.ID
I would like the results to be like:
I have already looked at Pivot, but it doesn't resolve my issue
Use window function:
select case when row_number() over(partition by emp.name order by empC.ID) = 1
then Name
else '' end as Name,
Comment
from Employee emp
left join EmployeeComments empC On empC.EmployeeID = emp.ID
This might give you some kind of order in your result window at least
WITH cte AS(
SELECT emp.Name ,
empC.Comment,
RANK() OVER (ORDER BY emp.Name) NameOrder,
ROW_NUMBER() OVER (PARTITION BY emp.Name ORDER BY empC.ID) RN
FROM Employee emp
LEFT JOIN EmployeeComments empC ON empC.EmployeeID = emp.ID
)
SELECT
Name = (CASE WHEN RN = 1 THEN Name ELSE '' END),
Comment
FROM
cte
ORDER BY
NameOrder,
RN
"use Cross Join:"
Query:
select case t.cnt
when 1 then
coalesce(t.Name,' ')
end as Name,t.comment
from
(
select t1.Name,t2.comment,row_number()
over(partition by t1.name order by t1.Name)
as cnt
from
EmployeeComments t1
cross join
Employee t2
where t1.ID=t2.Employeeid
)t

Resources