SQL Query group by in case statement - sql

I Have three tables like bellow
**tRole**
+--------+----------+-----------+
| RoleID | RoleCode | RoleTitle |
+--------+----------+-----------+
| 1 | Role1 | RT1 |
| 2 | Role2 | RT2 |
| 3 | Role3 | RT3 |
+--------+----------+-----------+
**tEmployee**
+-------+-------+
| EmpID | Name |
+-------+-------+
| 1 | Emp 1 |
| 2 | Emp 2 |
| 3 | Emp 3 |
+-------+-------+
**tEmployeeRole**
+-------+--------+
| EmpID | RoleID |
+-------+--------+
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
| 2 | 2 |
| 3 | 3 |
+-------+--------+
I want a output like below ,If a role mapped with only one employee then employee name will show other wise Multiple will show.
+--------+----------+-----------+----------+
| RoleID | RoleCode | RoleTitle | Employee |
+--------+----------+-----------+----------+
| 1 | Role1 | RT1 | Multiple |
| 2 | Role2 | RT2 | Multiple |
| 3 | Role3 | RT3 | Emp 3 |
+--------+----------+-----------+----------+
I write bellow query but when I group by emp.First_Name then the result is wrong
select cr.RoleCode,cr.RoleID,
case
when count(ear.RoleID)=1 then emp.First_Name
else 'M' end as 'AssignedTO'
from tRole as cr
left outer join tEmployeeRole as ear on cr.RoleID=ear.RoleID
left outer join tEmployee as emp on ear.EmployeeID=emp.EmployeeID
group by cr.RoleCode,crRoleID,emp.First_Name

Hello You can use this query for your solution :
you need to count with partition and use distinct data
DECLARE #tRole TABLE (
RoleID INT
,RoleCode VARCHAR(50)
,RoleTitle VARCHAR(50)
)
DECLARE #tEmployee TABLE (
EmpID INT
,EmpName VARCHAR(50)
)
DECLARE #tEmployeeRole TABLE ( EmpID INT, RoleID INT )
INSERT #tRole ( RoleID, RoleCode, RoleTitle )
SELECT 1, 'Role1', 'RT1'
UNION
SELECT 2, 'Role2', 'RT2'
UNION
SELECT 3, 'Role3', 'RT3'
INSERT #tEmployee ( EmpID, EmpName )
SELECT 1, 'Epm 1'
UNION
SELECT 2, 'Epm 2'
UNION
SELECT 3, 'Epm 3'
INSERT #tEmployeeRole ( EmpID, RoleID )
SELECT 1, 1
UNION
SELECT 1, 2
UNION
SELECT 2, 1
UNION
SELECT 2, 2
UNION
SELECT 3, 3
SELECT DISTINCT tRole.RoleID
, RoleCode
, RoleTitle
, CASE WHEN COUNT(tEmployeeRole.EmpID) OVER ( PARTITION BY tEmployee.EmpID ) = 1 THEN tEmployee.EmpName ELSE 'Multiple'END [Employee]
FROM #tEmployee tEmployee
LEFT OUTER JOIN #tEmployeeRole tEmployeeRole ON tEmployeeRole.EmpID = tEmployee.EmpID
LEFT OUTER JOIN #tRole tRole ON tRole.RoleID = tEmployeeRole.RoleID

You can Modify the answer from #Pratik to add a col that lists the employees
;with CTE as(
SELECT
DISTINCT tRole.RoleID
RoleCode
, RoleTitle
, CASE WHEN COUNT(tEmployeeRole.EmpID) OVER ( PARTITION BY tEmployee.EmpID ) = 1 THEN tEmployee.EmpName ELSE 'Multiple'END [Employee]
FROM #tEmployee tEmployee
LEFT OUTER JOIN #tEmployeeRole tEmployeeRole ON tEmployeeRole.EmpID = tEmployee.EmpID
LEFT OUTER JOIN #tRole tRole ON tRole.RoleID = tEmployeeRole.RoleID
)
select *
,stuff( (select ','+EmpName from #tEmployee IE inner join #tEmployeeRole IER on IE.EmpID = IER.EmpID where IER.RoleID = CTE.rolecode for xml PATH('') ),1,1,'') AS EMList
from CTE

This query might help you out . Make a try
Your Tables Data looks like
create TABLE #tRole (RoleID INT ,RoleCode VARCHAR(50) ,RoleTitle VARCHAR(50) )
create TABLE #tEmployee (EmpID INT ,EmpName VARCHAR(50) )
create TABLE #tEmployeeRole( EmpID INT, RoleID INT )
INSERT #tRole ( RoleID, RoleCode, RoleTitle )
SELECT 1, 'Role1', 'RT1'
UNION
SELECT 2, 'Role2', 'RT2'
UNION
SELECT 3, 'Role3', 'RT3'
INSERT #tEmployee ( EmpID, EmpName )
SELECT 1, 'Epm 1'
UNION
SELECT 2, 'Epm 2'
UNION
SELECT 3, 'Epm 3'
INSERT #tEmployeeRole ( EmpID, RoleID )
SELECT 1, 1
UNION
SELECT 1, 2
UNION
SELECT 2, 1
UNION
SELECT 2, 2
UNION
SELECT 3, 3
Desired Query
;with cte as
(
select tr.roleid,tr.rolecode,tr.roletitle,te.empname
,COUNT(ter.EmpID) OVER ( PARTITION BY ter.EmpID ) as emp_count
from #tEmployee te
inner join #tEmployeeRole tER on tER.empid=te.empid
inner join #tRole tr on tr.roleid=ter.roleid
)
select distinct RoleID,RoleCode,RoleTitle
,case when emp_count>1 then 'Multiple' else empname end as Employee
from cte

Related

Adding new data in columns, from another table - SQL ORACLE

I have a table with some records
MASTER TABLE
x------x--------------------x-------x
| Id | PERIOD | QTY |
x------x--------------------x-------x
| 1 | 2014-01-13 | 10 |
| 2 | 2014-01-06 | 30 |
x------x--------------------x-------x
I have another table with parameters of this record (ID)
TABLE2
x------x--------------------x------------x
| Id | Parameter | Value |
x------x--------------------x------------x
| 1 | Humidty | 10 |
| 1 | Temperature | 30 |
| 2 | Humidty | 50 |
| 2 | Temperature | 40 |
x------x--------------------x------------x
As result I want this: (combine based on ID)
Result table
x------x--------------------x-------------------------x
| Id | Period | Humidty | Temperature |
x------x--------------------x-------------------------x
| 1 | 2014-01-13 | 10 | 30 |
| 2 | 2014-01-06 | 50 | 40 |
x------x--------------------x-------------------------x
How Can I do something like that? Inner join will not work I think.
Join the tables and use conditional aggregation with case to extract the 2 columns:
select t1.id, t1.period,
max(case when t2.parameter = 'Humidty' then t2.value end) Humidty,
max(case when t2.parameter = 'Temperature' then t2.value end) Temperature
from mastertable t1 inner join table2 t2
on t2.id = t1.id
group by t1.id, t1.period
You can pivot:
SELECT * FROM
(
SELECT
t_m.Id
, t_m.Period
, t_2.Parameter
, t_2.Value
FROM #tbl_Master t_m
INNER JOIN #tbl_2 t_2 ON t_2.Id = t_m.Id
)AS t
PIVOT
(
MAX(t.Value)
FOR t.Parameter IN ([Humidity], [Temperature])
)pvt
and sample data:
DECLARE #tbl_Master TABLE
(
Id int,
Period Date,
QTY int
)
DECLARE #tbl_2 TABLE
(
Id int,
Parameter varchar(30),
[Value] int
)
INSERT INTO #tbl_Master
(
Id,
Period,
QTY
)
VALUES
(1, '2014-01-13', 10)
, (2, '2014-01-06', 30)
INSERT INTO #tbl_2
(
Id ,
Parameter ,
[Value]
)
VALUES
( 1, 'Humidity', 10)
, ( 1, 'Temperature' , 30)
, ( 2, 'Humidity', 50)
, ( 2, 'Temperature' , 40)
OUTPUT:
Id Period Humidity Temperature
1 2014-01-13 10 30
2 2014-01-06 50 40
Try this
DECLARE #Mastertable AS TABLE(Id INT,PERIOD DATE,QTY INT)
INSERT INTO #Mastertable
SELECT 1 ,'2014-01-13', 10 UNION ALL
SELECT 2 ,'2014-01-06', 30
DECLARE #Childtable AS TABLE(Id INT,Parameter VARCHAR(100), Value INT)
INSERT INTO #Childtable
SELECT 1 ,'Humidty' , 10 UNION ALL
SELECT 1 ,'Temperature' , 30 UNION ALL
SELECT 2 ,'Humidty' , 50 UNION ALL
SELECT 2 , 'Temperature' , 40
SELECT Id,Period,[Humidty],[Temperature]
FROM
(
SELECT c.Id,
m.PERIOD,
Parameter,
c.Value
FROM #Mastertable m
INNER JOIN #Childtable c
ON m.Id = c.Id
) AS srC
pivot
(MAX(Value) FOR Parameter IN ([Humidty],[Temperature])
) AS PVT
Result
Id Period Humidty Temperature
----------------------------------
1 2014-01-13 10 30
2 2014-01-06 50 40

Multiple counts on a single column SQL

I am currently running a query like the following:
SELECT a.ID, a.ContactID, a.Code,
FROM tableA a
JOIN (SELECT ContactID, Code
FROM tableA
WHERE ContactID IS NOT NULL
GROUP BY Code, ContactID
HAVING COUNT(Code) > 1) b
ON (a.Code = b.Code AND a.ContactID = b.ContactID)
WHERE a.ContactID IS NOT NULL
ORDER BY a.Code
This returns data that looks like the folloing:
table : a
+-------+-----------+-----------+
| ID | ContactID | Code |
+-------+-----------+-----------+
| 1 | 111 | abcd2 |
| 2 | 111 | abcd2 |
| 3 | 222 | abcd1 |
| 4 | 222 | abcd1 |
| 5 | 222 | abcd1 |
| 6 | 222 | abcd1 |
+-------+-----------+-----------+
So as you can see I get ContactID's that have more then one of the same Code.
The problem with this is, is that I don't want all this output (real table is much larger). I want a COUNT to go along side the Code column and just show one row for each iteration of Code. Like the following:
+-------+-----------+-----------+------+
| ID | ContactID | Code |COUNT |
+-------+-----------+-----------+------+
| 1 | 111 | abcd2 | 2 |
| 3 | 222 | abcd1 | 4 |
+-------+-----------+-----------+------+
Any help on this would be great and I hope I have explained my problem well enough. If not please ask for more information and if this has been answered before please point in that direction.
Thanks.
Your solution and other answers are way to complicated, you don't need the self join when you're simply aggregating with HAVING Count(x) > 1:
SELECT MIN(ID), ContactID, Code, COUNT(Code) AS [COUNT]
FROM tableA
WHERE ContactID IS NOT NULL
GROUP BY Code, ContactID
HAVING COUNT(Code) > 1
Full solution:
SQL Fiddle
CREATE TABLE TableA
([ID] int, [ContactID] int, [Code] varchar(5))
;
INSERT INTO TableA
([ID], [ContactID], [Code])
VALUES
(1, 111, 'abcd2'),
(2, 111, 'abcd2'),
(3, 222, 'abcd1'),
(4, 222, 'abcd1'),
(5, 222, 'abcd1'),
(6, 222, 'abcd1')
;
Query 1:
SELECT min(id), ContactID, Code, count(Code) as [COUNT]
FROM tableA
WHERE ContactID IS NOT NULL
GROUP BY Code, ContactID
HAVING COUNT(Code) > 1
Results:
| | ContactID | Code | |
|---|-----------|-------|---|
| 1 | 111 | abcd2 | 2 |
| 3 | 222 | abcd1 | 4 |
I would use exists instead of subquery :
select min(a.id) as id, a.ContactID, a.Code, count(*) as Cnt
from tableA a
where exists (select 1
from tableA a1
where a1.ContactID = a.ContactID and
a1.Code = a.Code and
a1.id <> a.id
)
group by a.ContactID, a.Code;
sub-query
select min(ID) as id, ContactID,Code,count(*) as cnt from
(SELECT a.ID, a.ContactID, a.Code
FROM tableA a
JOIN (SELECT ContactID, Code
FROM tableA
WHERE ContactID IS NOT NULL
GROUP BY Code, ContactID
HAVING COUNT(Code) > 1) b
ON (a.Code = b.Code AND a.ContactID = b.ContactID)
WHERE a.RetailContactID IS NOT NULL
ORDER BY a.Code
) t group ContactID,Code
;WITH CTE AS
(
SELECT a.ID, a.ContactID, a.Code,
FROM tableA a
JOIN (SELECT ContactID, Code
FROM tableA
WHERE ContactID IS NOT NULL
GROUP BY Code, ContactID
HAVING COUNT(Code) > 1) b
ON (a.Code = b.Code AND a.ContactID = b.ContactID)
WHERE a.RetailContactID IS NOT NULL
)
SELECT ID, ContactID, Code, COUNT(*) AS Cnt
FROM CTE
GROUP BY ID, ContactID, Code
ORDER BY 1, 2, 3
Extend your SQL query with one more grouping:
SELECT min(a.ID), a.ContactID, a.Code, count(*)
...
GROUP BY a.ContactID, a.Code
ORDER BY a.Code
Use group by in your select query
select x.ContactID, x.Code, [count] = count(x.id) from (
select id = 1 , ContactID = 111 , Code = 'abcd2' union all
select 2 , 111 , 'abcd2' union all
select 3 , 222 , 'abcd1' union all
select 4 , 222 , 'abcd1' union all
select 5 , 222 , 'abcd1' union all
select 6 , 222 , 'abcd1') x group by x.Code, x.ContactID

How to populate given SQL records to all UserID

I have a table in this form:
id | firstname | lastname | userid
---+-----------+------------------------
1 | john | smith | 545868-5434-343435-35353
2 | adam | finger | 545868-5434-343435-35353
3 | teri | marti | 545868-5434-343435-35353
4 | pei | port | 545868-5434-343435-35353
In the DB i have many userid i need to populate the very same firstname and lastname to all userid found in the Database
Here is my SQl Query
SELECT
cID, c.firstname,c.lastname,
[s].UserID,c.OwnerID
FROM
Customer INNER JOIN [s] ON c.OwnerID = [s].UserID AND c.AssignedtoID =
[s].UserID AND c.CreatedByUserID = [s].UserID
AssignedtoID is the same as UserID
is this helpful for you.?
Create table #tmpCustomer (id int, firstname VARCHAR(50),lastname VARCHAR(50),userid VARCHAR(100))
INSERT INTO #tmpCustomer
SELECT 1, 'john','smith','545868-5434-343435-35353'
union
SELECT 2,'adam','finger','545868-5434-343435-35353'
union
SELECT 3,'teri','marti','545868-5434-343435-35353'
union
SELECT 4, 'pei','port','545868-5434-343435-35353'
union
SELECT 5, 'abc','xyz','545868-5434-343435-35354'
union
SELECT 6, 'mno','ert','545868-5434-343435-35354'
--select * from #tmpCustomer
;with cte1 AS(Select row_number()over(partition by userid order by id) rn,* from #tmpCustomer ),
cte2 AS (select * from cte1 where rn=1 )
update t
set t.firstname=c.firstname
from #tmpCustomer t
JOIN cte2 c on t.userid=c.userid
select * from #tmpCustomer
drop table #tmpCustomer
i don't know if i good understand your question, try solution posted below
DECLARE #cust as table (firstname varchar(20),lastname Varchar(20))
Insert #cust
values
('Suzan','Smith')
declare #id as table (id int identity,anything varchar(20),row_inserted datetime2 default (cast(sysdatetime() as datetime2)))
INSERT #id
(anything,row_inserted)
SELECT 'x' ,'20180305'
union all
select 'y','20180305'
union all
select 'z','20180305'
select s.id,c.firstname,
c.lastname
from #id as s
cross join #cust as c

SQL recursive id nodes

I have a table structure like so
Id Desc Node
---------------------
1 A
2 Aa 1
3 Ab 1
4 B
5 Bb 4
6 Bb1 5
these Desc values are presented in a listview to the user, if the user chooses Bb, I want the ID 5 and also the ID 4 becuase thats the root node of that entry, simular to that if the user chooses Bb1, I need ID 6, 5 and 4
I am only able to query one level up, but there could be n levels, so my query at the moment looks like this
SELECT Id
FROM tbl
WHERE Desc = 'Bb1'
OR Id = (SELECT Node FROM tbl WHERE Desc = 'Bb1');
You can do this with Recursive CTE like below
Schema:
CREATE TABLE #TAB (ID INT, DESCS VARCHAR(10), NODE INT)
INSERT INTO #TAB
SELECT 1 AS ID, 'A' DESCS, NULL NODE
UNION ALL
SELECT 2 , 'AA', 1
UNION ALL
SELECT 3, 'AB', 1
UNION ALL
SELECT 4, 'B', NULL
UNION ALL
SELECT 5, 'BB', 4
UNION ALL
SELECT 6, 'BB1', 5
Now do recursive CTE for picking node value and apply it again on #TAB with a Join.
;WITH CTE AS(
SELECT ID, DESCS, NODE FROM #TAB WHERE ID=6
UNION ALL
SELECT T.ID, T.DESCS, T.NODE FROM #TAB T
INNER JOIN CTE C ON T.ID = C.NODE
)
SELECT * FROM CTE
When you pass 6 to the first query in CTE, the result will be
+----+-------+------+
| ID | DESCS | NODE |
+----+-------+------+
| 6 | BB1 | 5 |
| 5 | BB | 4 |
| 4 | B | NULL |
+----+-------+------+

Selecting all parents in the order of relation from hierarchical table SQL

I've a table like this with a parent child relation in the same table
AccountID| ParentID | AccountName
----------------------------------------------
1 | 0 | Root
2 | 1 | Child1
3 | 1 | Child2
4 | 2 | Child3
5 | 4 | Child1
6 | 5 | Child1
7 | 6 | Child1
8 | 6 | Child1
So when I send the account ID 7 I have to get the tables in the order like child,father,grandfather.. that way.. So for 7, I need to get all parets like this
AccountID
---------
7
6
5
4
2
1
So the most important point is the order. It should be from the bottom level to its next higher then to the next...
You can use a recursive CTE:
declare #childAccID int
set #childAccID = 7
;WITH Rec_CTE
AS(
SELECT 1 AS Level,
tChild.*
FROM dbo.TableName tChild
WHERE tChild.AccountID = #childAccID
UNION ALL
SELECT Level + 1 AS Level,
parent.*
FROM Rec_CTE tParent
INNER JOIN dbo.TableName parent
ON parent.AccountID = tParent.ParentID
)
SELECT * FROM Rec_CTE
ORDER BY Level
DEMO
Try this:
create table DemoTable
(
accountid bigint
,parentid bigint
,accountname nvarchar(128)
)
insert DemoTable(accountid,parentid,accountname)
select 1, null, 'Root'
union select 2, 1, 'Child1'
union select 3, 1, 'Child2'
union select 4, 1, 'Child3'
union select 5, 2, 'Child1.1'
union select 6, 2, 'Child1.2'
go
declare #findMe bigint = 6;
with myCTE as
(
select accountid,parentid,accountname,1 hierarchyLevel
from DemoTable
where accountid = #findMe
union all
select b.accountid,b.parentid,b.accountname, a.hierarchyLevel + 1
from myCTE a
inner join DemoTable b
on b.accountid = a.parentid
)
select * from myCTE
order by hierarchyLevel