sql pivot with dynamic columns - sql-server

i have already posted my question in the link sql group by order by and top in a same query the result for my request is,
SELECT
[Company Name],
[Designation],
[comp id],
[Employee Name]
FROM
(
SELECT emp.[Emp ID],
comp.[Company Name],
design.[Designation],
emp.[comp id],
emp.[Employee Name],
ROW_NUMBER() OVER (PARTITION BY emp.[Comp ID], emp.[Design ID] ORDER BY emp.[Comp ID] desc, emp.[Design ID] desc, emp.[Emp ID] desc) RowNum
from employee as emp
join designation as design on design.[Design ID]=emp.[Design ID]
join company as comp on comp.[Comp ID]=emp.[Comp ID]
) a
WHERE RowNum <=2
can anyone help me to pivot this query, thanks in advance

As you have a set number of employess in your list (from your comment) you don't need it to be dynamic. A regular pivot should do the trick:
select [Company Name],Emp1,Emp2,Emp3,Emp4 from (
SELECT
[Company Name],
[Employee Name],
'Emp' + cast(ROW_NUMBER() OVER (PARTITION BY [Comp ID] ORDER BY [Design ID], [Emp ID] desc) as char(2)) as RowNum
FROM
(
SELECT emp.[Emp ID],
comp.[Company Name],
design.[Designation],
emp.[Design ID],
emp.[comp id],
emp.[Employee Name],
ROW_NUMBER() OVER (PARTITION BY emp.[Comp ID], emp.[Design ID] ORDER BY emp.[Comp ID] desc, emp.[Design ID] desc, emp.[Emp ID] desc) RowNum
from employee as emp
join designation as design on design.[Design ID]=emp.[Design ID]
join company as comp on comp.[Comp ID]=emp.[Comp ID]
) a
WHERE RowNum <=2
) as pivotdata
pivot (max([Employee Name]) for [RowNum] in (Emp1,Emp2,Emp3,Emp4)) as P

Related

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')

Performance tuning on link server table joining with CTE

Want to tune the performance by reducing the number of SELECT on OPENQUERY by doing JOIN operation.
Here is how my query look like.
Query:
;WITH CTE AS
(
SELECT
[EmployeeFirstName], [EmployeeMiddleName],
[EmployeeLastName], [EmployeeAddress]
FROM
Employee
WHERE
[EmployeeSalary] >= 200000
)
SELECT
[First Name], [Fathers Husband Name], [Last Name], [Department Name]
FROM
OPENQUERY ([Depart], 'SELECT [First Name], [Fathers Name], [Last Name],[Department Name]
FROM Department
INNER JOIN CTE C1 ON PATINDEX(''[First Name]'',''C1.[EmployeeFirstName]'') > 0');
Error:
Invalid object name 'CTE'
Try the following
;WITH CTE AS
(
SELECT
[EmployeeFirstName], [EmployeeMiddleName],
[EmployeeLastName], [EmployeeAddress]
FROM
LocalServer.Database.Schema.Employee
WHERE
[EmployeeSalary] >= 200000
)
SELECT
[First Name], [Fathers Husband Name], [Last Name], [Department Name]
--It's better to specify the table eg: C1.ColumnName
FROM
(
SELECT [First Name], [Fathers Name], [Last Name],[Department Name]
FROM LinkedServer.Database.Schema.Department
INNER JOIN CTE C1
ON PATINDEX([First Name],C1.[EmployeeFirstName]) > 0
) TBL;

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]

Place Data from Same Column in Different Columns in Resultset

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

Did not receive expected results when using LEFT JOIN?

I have the following SQL statement, and it returns only 2 records even though I have 300 employees. Does anyone see what I could be doing wrong?
SELECT Employees.[Employee ID],
Employees.Employee,
Employees.[First Name],
Employees.[Middle Name],
Employees.[Last Name],
Employees.Position,
[Work].[Work ID]
FROM Employees LEFT JOIN
[Work] ON Employees.[Employee ID] = [Work].[Employee ID]
WHERE [Work].[Work Date] = '06-13-2012'
When using outer join filter on outer table must be applied in ON clause, otherwise you effectively get inner join:
SELECT
Employees.[Employee ID],
Employees.Employee,
Employees.[First Name],
Employees.[Middle Name],
Employees.[Last Name],
Employees.Position,
[Work].[Work ID]
FROM Employees
LEFT JOIN [Work]
ON Employees.[Employee ID] = [Work].[Employee ID]
AND [Work].[Work Date] = '06-13-2012'
If you want all employees, perhaps you are looking for something like:
SELECT Employees.[Employee ID], ...
FROM Employees LEFT JOIN
[Work] ON Employees.[Employee ID] = [Work].[Employee ID]
AND [Work].[Work Date] = '20120613'
Also note that you should use an unambiguous date format, e.g. yyyyMMdd
Have you checked the date in the Where clause?
Try converting into a datetime or check if you don't have hours/minutes/seconds defined in the [Work].[Work Date] column data.
Try removing the join to see where is the problem:
SELECT [Work].[Employee ID], [Work].[Work ID]
FROM [Work]
WHERE [Work].[Work Date] = '06-13-2012'
How many records you have like this?
Do all the Employee ID's match the ID's in Employees table?
If you need all the employees than you should do an LEFT OUTER JOIN:
SELECT Employees.[Employee ID],
Employees.Employee,
Employees.[First Name],
Employees.[Middle Name],
Employees.[Last Name],
Employees.Position,
[Work].[Work ID]
FROM Employees LEFT OUTER JOIN
[Work] ON Employees.[Employee ID] = [Work].[Employee ID]
AND [Work].[Work Date] = '06-13-2012'
Is this what you want?
Also try to check out [Work Date] column- if it also have time part (DateTime data type), then you should take that in account:
SELECT
Employees.[Employee ID],
Employees.Employee,
Employees.[First Name],
Employees.[Middle Name],
Employees.[Last Name],
Employees.Position,
[Work].[Work ID]
FROM Employees
LEFT JOIN [Work]
ON Employees.[Employee ID] = [Work].[Employee ID]
WHERE Convert(Char(10), [Work].[Work Date], 120) = '2012-06-13' -- can find better way

Resources