getting nested results from linq to sql - sql-server

my data looks like this in the table:
ID Name Parent ID
--- ---- ---------
1 Mike null
2 Steve 1
3 George null
4 Jim 1
I can't figure out how to write a linq to sql query that will return the results with the parent rows grouped with their child rows. So for example this is the result I want:
1 Mike (no parent)
2 Steve (Parent is 1)
4 Jim (Parent is 1)
3 George (no parent)
The way I'm doing it right now is to first grab a result set of all the parent rows. Then I loop through it and find the children for each parent and insert all this into a List<> as I loop. At the end the List<> has everything in the order I want it.
But is there a way to do this in just one linq query?

Assuming that you have a self-referential relationship for the table, you could do something like:
var q = db.People
.OrderBy( p => p.ParentID == null
? p.Name
: p.Parent.Name + ":" + p.ID + ":" + p.Name );

You need a Common Table Expression (CTE) to do recursive SQL. CTEs are not supported by Linq to Sql. You can execute a query directly though.
This is what the SQL might look like although it does not group the children with their parents. I don't think you can do the grouping using CTEs:
WITH DirectReports (ID, Name, ParentID, Level)
AS
(
SELECT e.ID, e.Name, e.ParentID, 0 AS Level
FROM Employee e
WHERE e.ParentID IS NULL
UNION ALL
SELECT e.ID, e.Name, e.ParentID, Level + 1
FROM Employee E
JOIN DirectReports AS d
ON e.ParentID = d.ID
)
SELECT *
FROM DirectReports

Related

Getting non-deterministic results from WITH RECURSIVE cte

I'm trying to create a recursive CTE that traverses all the records for a given ID, and does some operations between ordered records. Let's say I have customers at a bank who get charged a uniquely identifiable fee, and a customer can pay that fee in any number of installments:
WITH recursive payments (
id
, index
, fees_paid
, fees_owed
)
AS (
SELECT id
, index
, fees_paid
, fee_charged
FROM table
WHERE index = 1
UNION ALL
SELECT t.id
, t.index
, t.fees_paid
, p.fees_owed - p.fees_paid
FROM table t
JOIN payments p
ON t.id = p.id
AND t.index = p.index + 1
)
SELECT *
FROM payments
ORDER BY 1,2;
The join logic seems sound, but when I join the output of this query to the source table, I'm getting non-deterministic and incorrect results.
This is my first foray into Snowflake's recursive CTEs. What am I missing in the intermediate result logic that is leading to the non-determinism here?
I assume this is edited code, because in the anchor of you CTE you select the fourth column fee_charged which does not exist, and then in the recursion you don't sum the fees paid and other stuff, basically you logic seems rather strange.
So creating some random data, that has two different id streams to recurse over:
create or replace table data (id number, index number, val text);
insert into data
select * from values (1,1,'a'),(2,1,'b')
,(1,2,'c'), (2,2,'d')
,(1,3,'e'), (2,3,'f')
v(id, index, val);
Now altering you CTE just a little bit to concat that strings together..
WITH RECURSIVE payments AS
(
SELECT id
, index
, val
FROM data
WHERE index = 1
UNION ALL
SELECT t.id
, t.index
, p.val || t.val as val
FROM data t
JOIN payments p
ON t.id = p.id
AND t.index = p.index + 1
)
SELECT *
FROM payments
ORDER BY 1,2;
we get:
ID INDEX VAL
1 1 a
1 2 ac
1 3 ace
2 1 b
2 2 bd
2 3 bdf
Which is exactly as I would expect. So how this relates to your "it gets strange when I join to other stuff" is ether, your output of you CTE is not how you expect it to be.. Or your join to other stuff is not working as you expect, Or there is a bug with snowflake.
Which all comes down to, if the CTE results are exactly what you expect, create a table and join that to your other table, so eliminate some form of CTE vs JOIN bug, and to debug why your join is not working.
But if your CTE output is not what you expect, then lets help debug that.

SQL Select Count Statement

I have two tables, one for Employees and the second for records. I want to get total entries for each employee and order the results by max total entry like:
Daniel 3
David 1
tblEmployee:
EID Name
1 Daniel
2 David
tblEntry:
ID Column1 EID
1 XX 1
2 XX 1
3 XX 2
4 XX 1
try this:
select emp.EID,emp.Name,COUNT(etr.EID)
as total_entries from Employee emp join Entry etr
on emp.EID=etr.EID
group by emp.EID,emp.Name
You must use group by
select count(*) from tblEmployee ee, tblEntry e where ee.eid = e.eid group by ee.name
There are several variations on this, and you don't say what version of SQL Server you're using, but I like doing it this way:
;
using A
as (
select EID
, RecordCount = COUNT(*)
from tblEntry
group by
EID
)
select a.EID
, e.Name
, a.RecordCount
from A
join tblEmployee e
on A.EID = e.EID
order by
RecordCount desc
I like doing it this way rather than joining and then summarizing because you only have to group on the minimum number of fields. EID in tblEntry is likely to already have an index on it, while Name in tblEmployee may not.

I need all the employee under a supervisor

i have a below described situation
EmpID Name SupervisorID
1 A 9
2 B 8
3 C 1
4 D 3
I need all the employees under supervisor ID 1
Here EmployeeID 3 is under 1 i need 4 is is also under 3
Following output is required.
EmpID Name SupervisorID
3 C 1
4 D 3
You need to Use Recursive CTE for this.Try this,
With CTE as
(
select EmpID,Name,SupervisorID from Emp
where SupervisorID =1
Union All
select a.EmpID,a.Name,a.SupervisorID from Emp as a
inner join CTE b on a.SupervisorID= b.EmpID
)
select * from CTE
Fiddle Demo Here
Please take a look at this question also, it is same like your question. Sql server CTE and recursion example
Nobody expects the Spanish Inquisition a HierarchyId. These days, whenever I see an org structure (like the one you have here), I reach for the HierarchyId datatype. In essence, it allows you to answer questions like "which value(s) are 'under' this one?" and "which value(s) does this one belong to?". Here's how I'd implement it:
alter table dbo.Employee add OrgStructure HierarchyId null;
with h as (
select EmployeeId, SupervisorId, '/' + cast(EmployeeId as varchar) + '/' as h
from dbo.Employee as e
where e.SupervisorId is null --employees w/o a supervisor
union all
select e.EmployeeId, e.SupervisorId, h.h + '/' + cast(EmployeeId as varchar) + '/'
from dbo.Employee as e
join h
on e.SupervisorId = h.SupervisorId
)
update e
set OrgStructure = h.h
from dbo.Employee as e
join h
on e.EmployeeId = h.EmployeeId;
create index [IX_Employee_OrgStructure] on dbo.Employee (OrgStructure)
Now that the heavy lifting is done, actually answering your problem is trivial:
select *
from dbo.Employee as supervisor
join dbo.Employee as reports
on reports.OrgStructure.IsDescendantOf(supervisor.OrgStructure)
where supervisor.EmployeeId = 1
The advantage that I see is that you're not calculating the hierarchy on the fly every time you need to answer this type of question. You do it once and you're done.

Common Table Expression basic example

I have a recursive tree database table
DataItem
Id (uniqueidentifier)
Parent_Id? (uniqueidentifier)
PositionInParent (int)
I've read some articles about Common Table Expressions, which allows me to recursively read the tree structure directly from SQL database, but all of them are very complicated and i cannot make them work.
I am trying to read recursively all the DataItems, starting from the root ones (which has no parent), and adding the children items (ordered by PositionInParent)
Please help me create this simple example, and from there i will add more logic if necessary.
;WITH HierarchyCTE (ParentId, Id, Level)
AS
(
SELECT e.ParentId, e.Id, 0 AS Level
FROM Employees AS e
WHERE ParentId IS NULL
UNION ALL
SELECT e.ParentId, e.Id, Level + 1
FROM Employees AS e
INNER JOIN HierarchyCTE AS h
ON e.ParentId = h.Id
)
SELECT ParentId, Id, Level AS PositionInParent
FROM HierarchyCTE
You can use condition WHERE ParentId = 0if ParentId of super parent is 0

Get union of two table and taking data with a condition

I have two tables
table-a
id name
100 asd
101 ass
102 gdd
103 hgf
104 cvd
105 erf
table-b
id filter
100 red
101 blue
100 green
100 yellow
102 black
102 red
103 dark
Table-a is the master table and that have all the id's.but Table two is the one which has 'filter' data.
from these two table I want to find out all those 'id's which does not have minimum 2 filters.
note that table-b does not have all the itemnumbers in table-a, and i want all that itemnumber irrespective of if that is in table-a or table-b.I have tried inner joining these two tables and getting data out but nothing worked.
Select A.ID, A.Name, count(*)
from tableA A
LEFT JOIN tableB B on A.ID = B.ID
Group By A.ID, A.name
having count(*) <= 1
LEFT JOIN gives all records from A and only those in B which match.
The group by ID and name let us count the number of filters found in
each
The having says give me any items with a count less than or
equal to 1. (or less than the minimum 2)
Thus results would be.
101 ass 1
103 hgf 1
104 cvd 0
105 erf 0
select
*
from
table-a a
left join (
select id, count(id) as c from table-b group by id
) v on a.id = v.id
where isnull(v.id, 0) < 2
I think this would work in SQL Server (tested in SQLite and usually the two are fairly compatible when it comes to inline view syntax). But syntax issues aside, inline views can make working with sets easier to visualize.
select TA.id, name
from TA
inner join
(
select id from TA
where not exists (select id from TB where TA.id = TB.id)
UNION
select id from TB
group by id having count(filter) < 2
) as FOO
on TA.id = FOO.id
The default behavior of UNION is to remove duplicates.
The first UNIONed set consists of the ids from table A that have no filter (no counterpart in the filters table B).
The second UNIONed set consists of the ids from the filters table, table B, that have only 1 filter.
We inner join those unioned sets back to Table A to get the entity Name.

Resources