Linq, Left Join and Dates - linq

So my situation is that I have a linq-to-sql model that does not allow dates to be null in one of my tables. This is intended, because the database does not allow nulls in that field. My problem, is that when I try to write a Linq query with this model, I cannot do a left join with that table anymore because the date is not a 'nullable' field and so I can't compare it to "Nothing".
Example:
There is a Movie table, {ID,MovieTitle}, and a Showings table, {ID,MovieID,ShowingTime,Location}
Now I am trying to write a statement that will return all those movies that have no showings. In T.SQL this would look like:
Select m.*
From Movies m Left Join Showings s On m.ID = s.MovieID
Where s.ShowingTime is Null
Now in this situation I could test for Null on the 'Location' field but this is not what I have in reality (just a simplified example). All I have are non-null dates.
I am trying to write in Linq:
From m In dbContext.Movies _
Group Join s In Showings on m.ID Equals s.MovieID into MovieShowings = Group _
From ms In MovieShowings.DefaultIfEmpty _
Where ms.ShowingTime is Nothing _
Select ms
However I am getting an error saying
'Is' operator does not accept operands of type 'Date'. Operands must be reference or nullable types.
Is there any way around this? The model is correct, there should never be a null in the Showings:ShowTime table. But if you do a left join, and there are no show times for a particular movie, then ShowTime SHOULD be Nothing for that movie...
Thanks everyone for your help.

Using a left join isn't really helping you here. Since there can never be any results in the right-hand table, you might as well just retrieve the left-hand table and only the left. This is a simple "not in" / "not exists" query:
From m in dbContext.Movies _
Where Not dbContext.Showings.Any(Function(s) s.MovieID = m.MovieID) _
Select m

If there is no record in the Showings table, then the entire object in the query should be nothing. The date should never come into play under such a scenario. A left join would be written like this, selecting only the movies where the showing is missing
Dim query = From m In dbContext.Movies _
Group Join s In dbContext.Showing On m.ID Equals s.MovieID Into g = Group _
From item In g.DefaultIfEmpty() _
Where item Is Nothing _
Select m

Related

Trying to update a field in Oracle based on a select statement - getting subquery returns more than one row error

I am trying to update a field on a table the query needs to get the value from a 2nd table and use that to get the data from a 3rd table. I keep getting the "ORA-01427: single-row subquery returns more than one row" Any help is appreciated.
update ord_detail set cuser1 = (select c.email from contact c,ord_detail m join orders o on o.ID = m.orders_ID where c.email is not null)
where EXISTS (select email from contact,orders where orders.contact_id2 = contact.id)
Since you did not provide further information like the results of your sub selects, it's not 100% clear what exactly is your problem. You should check those results and if this does not answer your question, please provide the details.
My guess is that this sub query will give multiple rows because you are missing a join from the table "contact" to one of the other tables:
select c.email from contact c,ord_detail m
join orders o on o.ID = m.orders_ID where c.email is not null
Therefore, this sub query will always lead to many rows as result unless the table "contact" contains one row only whose column email is not null.

PL SQL - Join 2 tables and return max from right table

Trying to retrive the MAX doc in the right table.
SELECT F43.PDDOCO,
F43.PDSFXO,
F43.PDLNID,
F43.PDAREC/100 As Received,
F431.PRAREC/100,
max(F431.PRDOC)
FROM PRODDTA.F43121 F431
LEFT OUTER JOIN PRODDTA.F4311 F43
ON
F43.PDKCOO=F431.PRKCOO
AND F43.PDDOCO=F431.PRDOCO
AND F43.PDDCTO=F431.PRDCTO
AND F43.PDSFXO=F431.PRSFXO
AND F43.PDLNID=F431.PRLNID
WHERE F431.PRDOCO = 401531
and F431.PRMATC = 2
and F43.PDLNTY = 'DC'
Group by
F43.PDDOCO,
F43.PDSFXO,
F43.PDLNID,
F43.PDAREC,
F431.PRAREC/100
This query is still returning the two rows in the right table. Fairly new to SQL and struggling with the statement. Any help would be appreciated.
Without seeing your data it is difficult to tell where the problem might so I will offer a few suggestions that could help.
First, you are joining with a LEFT JOIN on the PRODDTA.F4311 but you have in the WHERE clause a filter for that table. You should move the F43.PDLNTY = 'DC' to the JOIN condition. This is causing the query to act like an INNER JOIN.
Second, you can try using a subquery to get the MAX(PRDOC) value. Then you can limit the columns that you are grouping on which could eliminate the duplicates. The query would them be similar to the following:
SELECT F43.PDDOCO,
F43.PDSFXO,
F43.PDLNID,
F43.PDAREC/100 As Received,
F431.PRAREC/100,
F431.PRDOC
FROM PRODDTA.F43121 F431
INNER JOIN
(
-- subquery to get the max
-- then group by the distinct columns
SELECT PDKCOO, max(PRDOC) MaxPRDOC
FROM PRODDTA.F43121
WHERE PRDOCO = 401531
and PRMATC = 2
GROUP BY PDKCOO
) f2
-- join the subquery result back to the PRODDTA.F43121 table
on F431.PRDOC = f2.MaxPRDOC
AND F431.PDKCOO = f2.PDKCOO
LEFT OUTER JOIN PRODDTA.F4311 F43
ON F43.PDKCOO=F431.PRKCOO
AND F43.PDDOCO=F431.PRDOCO
AND F43.PDDCTO=F431.PRDCTO
AND F43.PDSFXO=F431.PRSFXO
AND F43.PDLNID=F431.PRLNID
AND F43.PDLNTY = 'DC' -- move this filter to the join instead of the WHERE
WHERE F431.PRDOCO = 401531
and F431.PRMATC = 2
If you provide your table structures and some sample data, it will be easier to determine the issue.

Best way to exclude records from multiple tables

I got the following tables (just an example): vehicles, vehicle_descriptions, vehicle_parts
vehicles have 1 to many with vehicle_descriptions and vehicle_parts. There may not be a corresponding vehicle_description/part for a given vehicle.
SELECT * FROM vehicles
LEFT OUTER JOIN vehicles d ON vehicles.vin = d.vin AND d.summary NOT LIKE 'honda'
LEFT OUTER JOIN
(SELECT SUM(desc_total) FROM vehicle_descriptions WHERE NOT LIKE desc 'honda' GROUP BY vin) b
ON vehicles.vin = vehicle_b.vin
LEFT OUTER JOIN
(SELECT SUM(part_count) FROM vehicle_parts WHERE part_for NOT LIKE 'honda' GROUP BY vin) c ON vehicles.vin = c.vin
If either vehicle_desc, vehicles, or part contains the exclusion term, the whole record should not show up in the result set. The query above will return a record even if one of the tables contain the exclusion term Honda. How would I fix the above query?
You're not using any of the information in either sum() as part of what you show, just to decide whether to include the vehicle. And you're doing an unnecessary self join in your first clause. Generally in situations like this, the "exists" and "not exists" clauses work well. So what about this? I'll use Oracle syntax, you can convert to ANSI of course.
SELECT * FROM vehicles v where summary <> 'honda'
and not exists (select 1 from vehicle_descriptions d where d.vin = v.vin and d.desc <> 'honda')
and not exists (select 1 from vehicle_parts p where p.vin = v.vin and p.part_for <> 'honda')

Linq To Entity Framework selecting whole tables

I have the following Linq statement:
(from order in Orders.AsEnumerable()
join component in Components.AsEnumerable()
on order.ORDER_ID equals component.ORDER_ID
join detail in Detailss.AsEnumerable()
on component.RESULT_ID equals detail.RESULT_ID
where orderRestrict.ORDER_MNEMONIC == "MyOrderText"
select new
{
Mnemonic = detail.TEST_MNEMONIC,
OrderID = component.ORDER_ID,
SeqNumber = component.SEQ_NUM
}).ToList()
I expect this to put out the following query:
select *
from Orders ord (NoLock)
join Component comp (NoLock)
on ord .ORDER_ID = comp.ORDER_ID
join Details detail (NoLock)
on comp.RESULT_TEST_NUM = detail .RESULT_TEST_NUM
where res.ORDER_MNEMONIC = 'MyOrderText'
but instead I get 3 seperate queries that select all rows from the tables. I am guessing that Linq is then filtering the values because I do get the correct values in the end.
The problem is that it takes WAY WAY too long because it is pulling down all the rows from all three tables.
Any ideas how I can fix that?
Remove the .AsEnumerable()s from the query as these are preventing the entire query being evaluated on the server.

Linq to SQL: order by value in related table

I have 2 tables which in simplified form look like this:
Products(
id: int,
name: varchar
);
ProductSpecs(
product_id: int,
spec_name: varchar,
spec_value: int
);
Now I need to sort products (in linq to sql) by value of some specification item (eg. "price"). So I do something like this
var products = from p in db.Products
from ps in p.ProductsSpecs
where ps.spec_name == "price"
orderby ps.spec_value
select p;
The problem is that if there's no such ProductSpec with spec_name "price" the product is not included at all. I can add these products with Union or Concat but this way the sorting of the first part is not preserved.
What is the best way to deal with this?
Thanks.
First, I would recommend that you either do this in pure SQL as a function or Stored Procedure and then access this through linq, or add a price column to your product table. It seems like price would be a normal attribute to add to all of your products even if that price is NULL.
SQL:
select p.*
from products p
left outer join productspecs ps on
p.id = ps.product_id
and ps.spec_name = 'Price'
order by ps.spec_value
With that said, here's the weird bit of LINQ that should work on your table (I might have some of the column names spelled incorrectly):
var products = from p in db.Products
join ps in (from pss in db.ProductSpecs
where pss.spec_name== "Price"
select pss
) on p.id equals ps.product_id into temp
from t in temp.DefaultIfEmpty()
orderby t.spec_value
select p;
I tested this on some tables setup like above and created 5 products, three with prices in different value orders and this LINQ ordered them just like the SQL above and returned the null result rows as well.
Hope this works!
In ordinary SQL, you'd use an LEFT OUTER JOIN. This preserves rows that appear in the left-hand table (the one listed first), even when there's no matching row in the right-hand table (the second one listed, and the one that is outer joined). You end up with nulls for the values that should be, but weren't, present in the right-hand table. So, the price for those items missing a price would appear as NULL.
What that translates to in LINQ to SQL is another matter.
You might care to think about whether it is reasonable to have products that do not have a price. You're emulating something called EAV - Entity, Attribute, Value - tables, and they are generally regarded as 'not a good thing'.
Can you not just do a simple join?
var products =
from p in db.Products
join ps in db.ProductSpecs on p.id equals ps.product_id
where ps.spec_name == "price"
orderby ps.spec_value
select p;

Resources