Full outer join - Linq To SQL - linq-to-sql

I'm trying to use Linq to SQL to do a full outer join. I had this working for a basic example, but it didn't work when each side of the full outer join were generated from another inner join. Below's the code. I realise that this could probably be put into less queries - but I'd rather split them out to make them as readable as possible. Performance isn't an issue in this case.
var productIds = db.OrderItemsIncoming.Select(i => i.ProductID)
.Union(db.OrderItemsOutgoing.Select(o => o.ProductID))
.Distinct();
var ordersIn = from o in db.OrdersIncoming
join i in db.OrderItemsIncoming on o.OrderNumber equals i.OrderNumber
select new { o, i };
var ordersOut = from o in db.OrdersOutgoing
join i in db.OrderItemsOutgoing on o.OrderNumber equals i.OrderNumber
select new { o, i };
var fullOuterJoinResults = from i in ordersIn
join o in ordersOut on i.i.ProductID equals o.i.ProductID into t
from o in t.DefaultIfEmpty()
where i == null ^ o == null
select new { i, o };
In my test, the ordersIn results is empty, and the ordersOut results has one row in it. So I want the final fullOuterJoinResults to have a row, but it's empty.

Literally a second after I post, I notice an error where I'm not using the productID results anywhere!!! :-/ I'll edit this post with my fix once I've got it working ...
[edit]
Okay, this seems to work:
var ordersIn = from o in db.OrdersIncoming
join i in db.OrderItemsIncoming on o.OrderNumber equals i.OrderNumber
select new { o, i };
var ordersOut = from o in db.OrdersOutgoing
join i in db.OrderItemsOutgoing on o.OrderNumber equals i.OrderNumber
select new { o, i };
var productIds = db.OrderItemsIncoming.Select(i => i.ProductID)
.Union(db.OrderItemsOutgoing.Select(o => o.ProductID))
.Distinct();
var fullOuterJoinResults = from pid in productIDs
join i in ordersIn on pid equals i.i.ProductID into t1
from i in t1.DefaultIfEmpty()
join o in ordersOut on pid equals o.i.ProductID into t2
from o in t2.DefaultIfEmpty()
where i == null ^ o == null
select new { i, o };

Related

Linq to Sql 3 joins with group and min()

I'm trying to convert the SQL below to Linq. I haven't figured out the syntax for the GROUP BY, the MIN() or the extra organization join conditions.
SELECT DISTINCT o.OrganizationHierarchyUnitLevelThreeNm, o.OrganizationHierarchyUnitLevelFourNm, a.LabAssetSerialNbr, MIN(a.SystemCreatedOnDtm) MinCreated
FROM vw_DimLabAsset a
INNER JOIN vw_FactWorker w ON a.LabAssetAssignedToWorkerKey = w.WorkerKey
INNER JOIN vw_DimOrganizationHierarchy o ON w.OrganizationHierarchyKey = o.OrganizationHierarchyKey
AND o.OrganizationHierarchyUnitLevelThreeNm IS NOT NULL
AND o.OrganizationHierarchyUnitLevelFourNm IS NOT NULL
GROUP BY o.OrganizationHierarchyUnitLevelThreeNm, o.OrganizationHierarchyUnitLevelFourNm, a.LabAssetSerialNbr
This is what I've managed to get so far:
var pphw = from a in Vw_DimLabAsset
where a.LabAssetHardwareStatus != "Retired" && (a.LabAssetHardwareSubStatus == null || a.LabAssetHardwareSubStatus != "Archive") && types.Contains(a.LabAssetTypeNm) // (a.LabAssetTypeNm == "u_cmdb_ci_prototype_system" || a.LabAssetTypeNm == "u_cmdb_ci_silicon")
join w in Vw_FactWorker on a.LabAssetAssignedToWorkerKey equals w.WorkerKey
join o in Vw_DimOrganizationHierarchy on w.OrganizationHierarchyKey equals o.OrganizationHierarchyKey
select new { o.OrganizationHierarchyUnitLevelThreeNm, o.OrganizationHierarchyUnitLevelFourNm, a.LabAssetSerialNbr };
Here is how I would translate the query:
var ans = (from a in vw_DimLabAsset
join w in vw_FactWorker on a.LabAssetAssignedToWorkerKey equals w.WorkerKey
join o in vw_DimOrganizationHierarchy on w.OrganizationHierarchyKey equals o.OrganizationHierarchyKey
where o.OrganizationHierarchyUnitLevelThreeNm != null && o.OrganizationHierarchyUnitLevelFourNm != null
group new { o, a } by new { o.OrganizationHierarchyUnitLevelThreeNm, o.OrganizationHierarchyUnitLevelFourNm, a.LabAssetSerialNbr } into oag
select new {
oag.Key.OrganizationHierarchyUnitLevelThreeNm,
oag.Key.OrganizationHierarchyUnitLevelFourNm,
oag.Key.LabAssetSerialNbr,
MinCreated = oag.Min(oa => oa.a.SystemCreatedOnDtm)
}).Distinct();

LINQ: Count Users in 3 way join

I'm having trouble with LINQ to SQL, which I think should not be too difficult.
In SQL I have a BusinessUnits, that get's divided in OrgUnits, and Users belong to an Org Unit.
I want to print the BusinessUnitID with the number of Users in each.
In SQL, it will probably look like this:
SELECT BusinessUnitID, Count(u.UserID)
FROM BusinessUnitsOrgUnits bu
INNER JOIN OrgUnits org on bu.OrgUnitID= org.OrgUnitID
INNER JOIN Users u on org.OrgUnitID = u.OrgUnitID
GROUP BY BusinessUnitID
But in LINQ I got this, but struggling to get the count correct.
var UsersPerBU = from bu in BusinessUnitsOrgUnits
join org in OrgUnits on bu.OrgUnitID equals org.OrgUnitID
join u in Users on org.OrgUnitID equals u.OrgUnitID
group bu by bu.BusinessUnitID into g
select new
{
BusinessUnitID = g.Key,
UserCount = Users.Count (us => us.OrgUnit.OrgUnitID == bu.OrgUnitID)
//here it complains that bu does not exist.
};
var UsersPerBU = from bu in BusinessUnitsOrgUnits
join org in OrgUnits on bu.OrgUnitID equals org.OrgUnitID
join u in Users on org.OrgUnitID equals u.OrgUnitID
group bu by bu.BusinessUnitID into g
select new
{
BusinessUnitID = g.Key,
UserCount = g.Count()
};
Maybe this
var UsersPerBU = (from bu in BusinessUnitsOrgUnits
join org in OrgUnits on bu.OrgUnitID equals org.OrgUnitID
join u in Users on org.OrgUnitID equals u.OrgUnitID
group bu by bu.BusinessUnitID into g
select new { bu = g})
.Select(x =>
new
{
BusinessUnitID = x,
UserCount = x.bu.Select(y => y.OrgUnitID).Distinct().Count()
//here it complains that bu does not exist
}
);

how i write this sql query to linq query

i just want to use LinqToSql classes query. here i just want to convert this sql query to appropriate linq query.
this is my sql query:
SELECT j.[JobID], p.[PreparedEmailID],
p.[Name] AS 'PreparedEmailName',
j.[CreatedOn], j.[CompletedOn],
j.[SubscriberCount], j.[EmailsSent],
(SELECT TOP 1 [Message] FROM
[LoggedMessages] WHERE [JobID] =
j.[JobID] ORDER BY [LoggedMessageID] DESC)
AS 'LoggedMessage' FROM [Jobs] AS j
INNER JOIN [PreparedEmails] AS p
ON p.[PreparedEmailID] =
j.[PreparedEmailID]
and my generated linq query is like:
var query = from j in db.Jobs
join p in db.PreparedEmails on j.PreparedEmailID equals p.PreparedEmailID
join l in db.LoggedMessages on j.JobID equals l.JobID into ej
from l in ej.DefaultIfEmpty() orderby l.LoggedMessageID descending
orderby l.LoggedMessageID descending
orderby j.CreatedOn descending
select new
{
JobID = j.JobID,
PreparedEmailID = p.PreparedEmailID,
PreparedEmailName = p.Name,
CreatedOn = j.CreatedOn,
CompletedOn = j.CompletedOn,
SubscriberCount = j.SubscriberCount,
EmailsSent = j.EmailsSent,
LoggedMsg = l.Message
};
I prepared some linQ query for you (but i didn't test it in VS because i have no access to it now, so please be careful because it can contain some errors):
var list = from Jobs
join PreparedEmails on Jobs.PreparedEmailID == PreparedEmails.PreparedEmailID
join LoggedMessages on LoggedMessages.JobID == Jobs.JobID
select
{
JobID = Jobs.JobID,
PreparedEmailID = PreparedEmails.PreparedEmailID,
PreparedEmailName = PreparedEmails.Name,
CreatedOn= Jobs.CreatedOn,
CompletedOn = Jobs.CompletedOn,
SubscriberCount = Jobs.SubscriberCount,
EmailsSent = Jobs.EmailsSent,
LoggedMessage = LoggedMessages.Message
} orderby descending LoggedMessages.LoggedMessageID;
It should help a little bit ...
this is solution:
var query = from j in db.Jobs
join p in db.PreparedEmails on j.PreparedEmailID equals p.PreparedEmailID
orderby j.CreatedOn descending
select new
{
JobID = j.JobID,
PreparedEmailID = p.PreparedEmailID,
PreparedEmailName = p.Name,
CreatedOn = j.CreatedOn,
CompletedOn = j.CompletedOn,
SubscriberCount = j.SubscriberCount,
EmailsSent = j.EmailsSent,
LoggedMsg = (from l in db.LoggedMessages
where j.JobID == l.JobID
orderby l.LoggedMessageID descending
select l.Message).FirstOrDefault()
};

Nested inner joins in linq to sql?

After quick overview I didn't find how to deal with linq to sql if I have several nested inner joins.
That's what I'd like to have in linq
SELECT Booking.BookingId, Booking.EventId, Booking.StartDate, Event.Name, Person.FirstName
FROM Booking
INNER JOIN Event
INNER JOIN Asset
ON Asset.AssetId = Event.AssetId
INNER JOIN Person
ON Person.PersonId = Event.ContactPersonId
ON Event.EventId = Booking.EventId AND Event.State = 4
Does anyone know how to translate it to LINQ?
Thanks.
var q1= from a in booking,b in event,c in asset, d in person where a.eventid=b.eventid and b.state=4 and c.assetid = b.assetid and b.contactpersonid=d.personid select a,b,c,d
you can replace a,b,c,d at then with the column names you want
another way is to use the join keyword:
var w1= from a in booking join b in event on a.eventid equals b.eventid join c in asset on ...
var query = from b in context.Bookings
from e in context.Events
join a in context.Assets on e.AssetId equals a.AssetId
join p in context.People on e.ContactPersonId equals p.PersonId
where e.State == (byte)States.Approved && e.EventId == b.EventId
select new { EventName = e.Name, BookingDate = b.StartDate };

Linq to SQL order by aggregate

I have a very simple grouping and aggregation problem in LINQ to SQL that I just can't figure out, and it is driving me mad.
I've simplified things into this example:
class Customer {
public Guid Id;
public String Name;
}
class Order {
public Guid Customer_Id;
public double Amount;
}
How do I get a list of customers ordered by the number of orders they have? And on the total amount they have purchased for?
return dataContext.Customers.OrderBy(cust => cust.Orders.Count)
.ThenBy(cust => cust.Orders.Sum(order => order.Amount))
.ToList();
var qry1 = from c in db.Customers
join o in db.Orders on c.Id equals o.Customer_Id into orders
orderby orders.Count()
select c;
var qry2 = from c in db.Customers
join o in db.Orders on c.Id equals o.Customer_Id into orders
orderby orders.Sum(o => o.Amount)
select c;
By number of orders:
var customers = (from c in db.Customers
select new
{
c.Name,
OrderCount = c.Orders.Count()
}).OrderBy(x => x. OrderCount);
By total amount purchased:
var customers = (from c in db.Customers
select new
{
c.Name,
Amount = (from order in c.Orders
select order.Amount).Sum()
}).OrderBy(x => x.Amount);