Find element in hierarchy - sql-server

I'm trying to create a hierarchical query using WITH of T-SQL. What I want to do is, for example, to find if John is a boss of Ryan, directly or indirectly?
How can I write a query for this?

WITH BossOf AS(
SELECT bossId, Id From Employees
UNION ALL
SELECT b.bossId, e.Id
FROM Employees AS e
INNER JOIN BossOf b ON b.Id = e.bossId
)
SELECT * FROM BossOf
WHERE Id = 'Ryan'
Just as an example of what you can do with BossOf...
WITH BossOf AS(
SELECT bossId, Id From Employees
UNION ALL
SELECT b.bossId, e.Id
FROM Employees AS e
INNER JOIN BossOf b ON b.Id = e.bossId
)
SELECT * FROM Employees
WHERE Id IN (SELECT BossId
FROM BossOf
Where Id = 'Ryan')
Or Even
WITH BossOf AS(
SELECT bossId, Id From Employees
UNION ALL
SELECT b.bossId, e.Id
FROM Employees AS e
INNER JOIN BossOf b ON b.Id = e.bossId
)
SELECT COUNT(*) FROM BossOf
WHERE Id = 'Ryan'
AND BossId = 'John'

Related

Column name doesn't exist in CTE statement

I'm trying to create a CTE statement:
WITH StartCash (StartCash) AS
(
SELECT StartCash
FROM CashierInfo
WHERE CashierID = (SELECT MAX( CashierID)
FROM CashierInfo
WHERE UserID = 1 AND EndDate IS NULL)
)
SELECT
StartCash, a.username AS Username, b.Adress AS Adress,
(SUM(c.quantity * c.discountprice)) AS SumPrice,
c.Printed AS Printed, c.CashierUserID AS CashierUserID,
c.RetailDelivery AS RetailDelivery, c.TrnDocumentID
FROM
Users a
JOIN
InventoryTransTemp c ON c.CashierUserID = a.UserID
JOIN
DeliveryAdress b ON b.DeliveryAdressID = c.DeliveryAdressID
WHERE
c.cashieruserid = 1
GROUP BY
a.Username, b.Adress, c.Printed,
c.CashierUserID, c.RetailDelivery, c.TrnDocumentID
But I am getting an error
Invalid column name 'StartCash'
StartCash does not exist because your CTE is not included in your FROM clause.
Based solely on what I can see in your question, I assume it would be safe to JOIN CashierInfo.UserID to Users.UserID.
So try something like this:
WITH StartCash
AS (
SELECT StartCash
,UserID
FROM CashierInfo
WHERE CashierID = (
SELECT MAX(CashierID)
FROM CashierInfo
WHERE UserID = 1
AND EndDate IS NULL
)
)
SELECT sc.StartCash
,a.username AS Username
,b.Adress AS Adress
,(SUM(c.quantity * c.discountprice)) AS SumPrice
,c.Printed AS Printed
,c.CashierUserID AS CashierUserID
,c.RetailDelivery AS RetailDelivery
,c.TrnDocumentID
FROM StartCash sc
INNER JOIN Users a ON sc.UserID = a.UserID
INNER JOIN InventoryTransTemp c ON c.CashierUserID = a.UserID
INNER JOIN DeliveryAdress b ON b.DeliveryAdressID = c.DeliveryAdressID
WHERE c.cashieruserid = 1
GROUP BY sc.StartCash
,a.Username
,b.Adress
,c.Printed
,c.CashierUserID
,c.RetailDelivery
,c.TrnDocumentID
You do not have the CTE in the from clause. You need to join to the CTE but your CTE has only a summary value. https://learn.microsoft.com/en-us/sql/t-sql/queries/with-common-table-expression-transact-sql?view=sql-server-2017

SQL Server - Filter data using a query which is dependent on another query

I have a query which returns few emmployee id's and the query looks like below
select E.EmpID as EmployeeID
from tblEmployee E
where EmpRole in (1,2,3) and E.Test like '%PS%'
I have another query which looks like below one
Select E.EmpID and EmployeeID, B.CountryId, B.CountryName, B.StateId,
B.StateName
from tblEmployeeInfo E
inner join tblTest B
where E.StateId = B.StateId and E.CountryId = B.CountryId
My requirement is that the second query needs to return data of only those employees which are resulted in 1st query...
Both are different tables, how can i join these both ?
use a Select inside the IN clause
Select E.EmpID as EmployeeID, B.CountryId, B.CountryName, B.StateId,
B.StateName
from tblEmployeeInfo E
inner join tblTest B
where E.StateId = B.StateId and E.CountryId = B.CountryId
and E.EmpID IN (select E.EmpID
from tblEmployee E
where EmpRole in (1,2,3) and E.Test like '%PS%'
)
You could do another JOIN in tblEmployee :
Select E.EmpID and EmployeeID, B.CountryId, B.CountryName, B.StateId,
B.StateName
from tblEmployeeInfo E
JOIN tblTest B ON E.StateId = B.StateId and E.CountryId = B.CountryId
JOIN tblEmployee E2 ON E.EmpID = E2.EmpID AND E2.EmpRole in (1,2,3) AND E2.Test like '%PS%'

sql - retrieve only first record using join

I have three tables: Employee, Contact, Employee_Contact
Employee:
EMP_ID, FIRST_NAME, LAST_NAME...
CONTACT:
CONTACT_ID, TELEPHONE, MOBILE...
EMPLOYEE_CONTACT:
EMP_ID, CONTACT_ID
Employee and Contact table is mapped with Employee_Contact table.
So I want to retrieve all Employees with Employee's only first contact, I tried this query but it is retrieving all the contacts related to that employee. Please check below query and let me know in case of any mistakes.
SELECT EMP.FirstName
,DEPT.Description AS Department
,CNT.Mobile
,CNT.Telephone
FROM MstEmp EMP
LEFT OUTER JOIN Department DEPT ON EMP.DeptID = DEPT.Department_ID
LEFT OUTER JOIN Employee_Contact EC ON EMP.EMP_ID = EC.EMP_ID
OUTER APPLY (
SELECT TOP 1 *
FROM Contact CONT
WHERE EC.Contact_ID = CONT.Contact_ID
) CNT
Use Top keyword retrieve top one record.
SELECT TOP 1 EMP.FirstName, DEPT.Description AS Department, CNT.Mobile,
CNT.Telephone
FROM MstEmp EMP
LEFT OUTER JOIN Department DEPT on EMP.DeptID = DEPT.Department_ID
LEFT OUTER JOIN Employee_Contact EC ON EMP.EMP_ID = EC.EMP_ID
OUTER APPLY(SELECT TOP 1 * FROM Contact CONT WHERE EC.Contact_ID =
CONT.Contact_ID)CNT
Try this one:
SELECT EMP.FirstName
,DEPT.Description AS Department
,t.Mobile
,t.Telephone
FROM MstEmp EMP
LEFT OUTER JOIN Department DEPT ON EMP.DeptID = DEPT.Department_ID
LEFT OUTER JOIN Employee_Contact EC ON EMP.EMP_ID = EC.EMP_ID
LEFT OUTER JOIN Contact CONT ON EC.Contact_ID = (
SELECT MIN(c.Contact_ID) c_id
FROM Contact c
WHERE CONT.Contact_ID = c.Contact_ID
) t
Give it a try:
select * from (
select E.[emp_id],
E.[first_name],
E.[last_name],
C.*,
RANK() over (partition by (E.[emp_id], E.[first_name], E.[last_name]) order by (select null)) [RN]
from Employee [E]
join employee_contact [EC] on E.[emp_id] = EC.[emp_id]
join contact [C] on EC.[contact_id] = C.[contact_id]
) A where RN = 1
You can use ROW_NUMBER() and get the first record for all the employees and then join it with the other tables.
SELECT EMP.FirstName,
DEPT.Description AS Department,
c.Mobile,
c.Telephone
FROM MstEmp EMP
LEFT OUTER JOIN Department DEPT ON EMP.DeptID = DEPT.Department_ID
INNER JOIN (
SELECT *,ROW_NUMBER() OVER (PARTITION BY EMP_ID ORDER BY EMP_ID) AS RN
FROM Employee_Contact ) EC ON EMP.EMP_ID = EC.EMP_ID
INNER JOIN Contact c ON c.Contact_ID=EC.Contact_ID
WHERE EC.RN=1

SQL query to fetch repeat column values within time frame

I have an eCommerce website where I am getting lot of fraud orders.. I'd like to pull out those Order_No.
Here is my query
SELECT
O.Order_No, O.Customer_ID, O.DateOrdered, O.IPAddress,
C.FirstName, C.LastName, CD.nameoncard
FROM
Order_No O
INNER JOIN
CardData CD ON O.card_id = CD.id
INNER JOIN
Customers C ON O.customer_id = C.customer_id
ORDER BY
O.order_no desc
Here's the criteria I want to follow:
If the customer_id repeats more than once in 6hrs
If the IPAddress repeats more than once in 6hrs
If the Lastname is NOT found in Nameoncard
Can someone help please?
can you try this
WITH Tmp (Order_No, Customer_id, DateOrdered, IPAddress, FirstName, LastName, NameOnCard)
AS
(
SELECT Ord.Order_No, Ord.Customer_Id, Ord.DateOrdered, Ord.IPAddress,
Cust.FirstName, Cust.LastName, CustData.NameOnCard
FROM Order_No Ord
INNER JOIN Customers Cust
ON
Cust.Customer_Id = Ord.Customer_Id
INNER JOIN
CardData CustData
ON CustData.Id = Ord.Card_Id
)
SELECT DISTINCT a.*
FROM Tmp a
INNER JOIN Tmp b
ON a.Order_No <> b.Order_No
AND a.Customer_Id = b.Customer_Id
WHERE DATEDIFF(hour, a.DateOrdered, b.DateOrdered) >= 6
UNION
SELECT DISTINCT c.*
FROM Tmp c
INNER JOIN Tmp d
ON c.Order_No <> d.Order_No
AND c.IPAddress = d.IPAddress
WHERE DATEDIFF(hour, c.DateOrdered, d.DateOrdered) >= 6
UNION
SELECT DISTINCT e.*
FROM Tmp e
WHERE ISNULL(e.NameOnCard,'') = ''
here is the query:
select * from
(
select b.order_no,b.dateordered,a.customer_id, C.FirstName, C.LastName, cd.nameoncard from order_no as a
left join order_no as b on a.customer_id=b.customer_id
inner join carddata as cd on b.customer_id=cd.customer_id
INNER JOIN Customers C ON b.customer_id = C.customer_id
where a.order_no < b.order_no
and datediff(hour,a.dateordered,b.dateordered) between 0 and 6
union
select b.order_no,b.dateordered,a.customer_id, C.FirstName, C.LastName, cd.nameoncard from order_no as a
left join order_no as b on a.IPAddress=b.IPAddress
inner join carddata as cd on b.customer_id=cd.customer_id
INNER JOIN Customers C ON b.customer_id = C.customer_id
where a.order_no < b.order_no
and datediff(hour,a.dateordered,b.dateordered) between 0 and 6
union
select a.order_no,a.dateordered,a.customer_id, C.FirstName, C.LastName, cd.nameoncard from order_no as a
inner join carddata as cd on a.customer_id=cd.customer_id
INNER JOIN Customers C ON a.customer_id = C.customer_id
where charindex(C.LastName,cd.nameoncard) = 0
) as abc

How to list duplicate records?

I have the following table structure:
id|date|studenttypeid|name|audituser
1|.....|4|Jason|....
2|.....|4|Robin|....
3|.....|4|Jason|....
4|.....|4|Dan|....
5|.....|4|Robin|....
I need to list all records which are duplicates on studenttypeid + name.
With the above data, the query should give me the following output:
1|.....|4|Jason|....
2|.....|4|Robin|....
3|.....|4|Jason|....
5|.....|4|Robin|....
How can I achieve this on SQL Server 2008?
You can use a group by and then join back to the original table, like this:
WITH Temp(StudentTypeId, Name) AS(
SELECT
StudentTypeId, Name
FROM YourTable
GROUP BY
StudentTypeId, Name
HAVING Count(1) > 1
)
SELECT YourTable.*
FROM YourTable
INNER JOIN Temp
ON YourTable.StudentTypeId = Temp.StudentTypeId
AND YourTable.Name = Temp.Name
you can use ROW_NUMBER()
SELECT ID, DATE, studenttypeid, name, audituser
FROM
(
SELECT ID, DATE, studenttypeid, name, audituser,
ROW_NUMBER() OVER (PARTITION BY studenttypeid, name
ORDER BY id) rn
FROM yourTableName
) a
WHERE rn = 1
SQLFiddle Demo
If you want to include every occurrence of the duplicates, some more methods using CROSS APPLY...
SELECT p.*
FROM people p
CROSS APPLY (
SELECT TOP(1) * FROM people p2 WHERE p2.ID <> p.ID AND p2.name = p.name AND p.studenttypeid = p2.studenttypeid
) as pWithDups
Or an EXISTS check
SELECT p.*
FROM people p
WHERE EXISTS (
SELECT *
FROM people p2
WHERE p2.ID <> p.ID AND p2.name = p.name AND p.studenttypeid = p2.studenttypeid
)
Try this
SELECT a.*
FROM yourtable a
JOIN (SELECT studenttypeid,
name
FROM yourtable
GROUP BY studenttypeid,
name
HAVING Count(studenttypeid) > 1) b ON b.name = a.name
ORDER BY a.id

Resources