Add value of subquery in Entity Framework - entity-framework

I have a really strange situation with the subquery.
Value of subquery is calculated but assigned value to property is different
var ozForAllViews = from oz in dbContext.oz
where
oz.TId == 6050
select
new ozForAllView
{
ozId = oz.ozId,
Ilosc = oz.Ilosc - (from pz in dbContext.pz
where
pz.Aktywny &&
pz.ozId == oz.ozId
select pz).Sum(z=> (decimal?) z.Ilosc) ?? 0
};
My property Ilosc is not calculated properly, value in DB equals 5.
But returned value is always 0.
Why is that oz.Ilosc is not subtracted from subquery?
I mean that 5 - 0 should equals 5.

You should surround the expression that calculates the subtracted amount by parentheses:
from oz in dbContext.oz
where oz.TId == 6050
select
new ozForAllView
{
ozId = oz.ozId,
Ilosc = oz.Ilosc - ((from pz in dbContext.pz
where
pz.Aktywny &&
pz.ozId == oz.ozId
select pz).Sum(z=> (decimal?) z.Ilosc) ?? 0)
};
This is because the query is translated into SQL. In SQL, if one part of an expression is null, the whole expression is null. Your query is translated such that oz.Ilosc - (from ... (decimal?) z.Ilosc) is evaluated as one expression. That part becomes null when the subtracted amount is null and hence it will be returned as 0.
It's confusing because in plain C# code, the behavior would be different. There the ?? 0 part would be applied to the subtracted amount only.

Related

How to catch null while summarizing records in EF6

next problem with Linq/EF6 queries.
I simply like to build a sum of some decimal fields:
var offsetHours1 = (from os in db.TimesheetOffsets
where (os.EmployeeId == employeeId && os.OffsetDate <= DateTime.Today)
select new
{
offset = os.OffsetHours
}).Sum(h=>h.offset);
So far it works, if I have records to sum but if the query returns null or no records, I get a System.InvalidOperationException
Is there an elegant way to summarize records in one step, so if there are no records, 0 is returned?
Thanks, Carsten
There's a quirk with the Sum extension method. As OffsetHours is a decimal, the overload of Sum you'll be using is Sum(..., decimal) which has this behaviour. To avoid it you can cast the value to a decimal? (nullable). With this you'll be using a different Sum that returns a nullable decimal and is OK with empty lists;
You can for example do this;
var offsetHours1 = (from os in db.TimesheetOffsets
where (os.EmployeeId == employeeId && os.OffsetDate <= DateTime.Today)
select os.OffsetHours)
.Sum(h => (decimal?)h);
Edit:
Removed unnecessary creation of anonymous type.

Why am I getting an error that I cannot concat two different datatypes even after casting the fields datatype

I have a query in postgresql where I want to append a minus sign to the transactions.amount field when the transaction.type = 2 (which refers to withdrawals). I am trying to concat a minus sign and the transactions.amount field which is an int. I casted the transactions.amount field to a text/varchar but no matter what I still get the error, "PostgreSql Error: case types numeric and text cannot be matched"
Here is the query I am running,
SELECT CAST(CASE WHEN "IsVoided" IS TRUE THEN 0
WHEN "Transactions"."TransactionType" = 2
THEN CONCAT('-', CAST("Transactions"."Amount" AS TEXT))
ELSE "Transactions"."Amount" END AS Text) AS "TransAmount"
FROM "Transactions"
LEFT JOIN "DepositSources"
ON "Transactions"."DepositSourceId" =
"DepositSources"."DepositSourceId"
LEFT JOIN "WithdrawalSources"
ON "Transactions"."WithdrawalSourceId" =
"DepositSources"."DepositSourceId"
WHERE "Transactions"."FundId" = 4
AND "Transactions"."ReconciliationId" = 24
What's very perplexing is when i run the below query it works as expected,
SELECT CONCAT('-', CAST("Transactions"."Amount" AS TEXT)) FROM
"Transactions"
All branches of a CASE expression need to have the same type. In this case, you're stuck with making all branches text, because what follows THEN can only be text. Try this version:
CASE WHEN IsVoided IS TRUE
THEN '0'
WHEN Transactions.TransactionType = 2
THEN CONCAT('-', Transactions.Amount::text)
ELSE Transactions.Amount::text END AS TransAmount
Note that it is unusual to be using the logic you have in a CASE expression. Typically, you would just be checking the values of a single column, not multiple different columns.
Edit:
It appears that your call to CONCAT mainly serves to negative a value. Here is one more simple way to do this:
CASE WHEN IsVoided IS TRUE
THEN 0
WHEN Transactions.TransactionType = 2
THEN -1.0 * Transactions.Amount
ELSE Transactions.Amount END AS TransAmount
In this case, we can make the CASE expression just generate numeric output, which might be really what you are after.

convert negative value to zero in T-SQL

How to convert negative values to zero in a calculated column?
we have inner join of multiple tables where a column is a calculated column taken from tables,i need to convert negative values present in the column to zero, how can i do?
what was tried..
i tried with 'case' condition but its not working.
part of code where i intend to change is similar to like this
(isnull((select isnull(sum(AVAILPHYSICAL),0) from ax.inventsum
where ITEMID = ax.INVENTTABLE.ITEMID ))-
(select isnull(sum(QTY*-1),0) from ax.RETAILTRANSACTIONSALESTRANS RTST inner join ax.RETAILTRANSACTIONTABLE RTT
on RTT.TRANSACTIONID = RTST.TRANSACTIONID
where ITEMID=ax.INVENTTABLE.ITEMID and (RTT.ENTRYSTATUS = 0 OR RTT.ENTRYSTATUS = 2) and
(RTST.TRANSACTIONSTATUS = 0 or
RTST.TRANSACTIONSTATUS = 2 ) and
As Quantity,

Count Group Ordinal in LINQ to Dataset

I have an old FoxPro program that does a SQL query which includes the following:
SELECT Region,
Year AS yr_qtr,
SUM(Stock) AS inventory
**...
COUNT(Rent) AS rent_ct
FROM
**...
GROUP BY Region, Year
ORDER BY Region, Year
INTO CURSOR tmpCrsr
The query is against a .DBF table file, and includes data from an Excel file. I've used both to populate an enumeration of user-defined objects in my C# program. (Not sure .AsEnumerable is needed or not.) I then attempt to use LINQ to Dataset to query the list of user objects and create the same result set:
var rslt1 = from rec in recs_list //.AsEnumerable()
group rec by new {rec.Region, rec.Year} into grp
select new
{
RegName = grp.Key.Region,
yr_qtr = grp.Key.Year,
inventory = grp.Sum(s => s.Stock),
// ...
rent_count = grp.Count(r => r.Rent != null)
};
This gives me the warning that "The result of the expression is always 'true' since a value of type 'decimal' is never equal to 'null' of type 'decimal'" for the Count() of the Rent column.
This makes sense, but then how do I do a count exclusive of the rows that have a value of .NULL. for that column in the FoxPro table (or NULL in any SQL database table, for that matter)? I can't do a null test of a decimal value.
If rent is based off of a column which is not a nullable value, then checking for null makes no sense which I believe the compiler accurately shows. Change the line to
rent_count = grp.Count(r => r.Rent != 0)
instead.
For if the code is actuall nullable such as:
Decimal? rent;
That would make checking rent against null valid. If that is the case then the line would be:
rent_count = grp.Count(r => (r.Rent ?? 0) != 0)
where null coalesding operator ?? can be used. Which states if r.rent is null, use the value 0 (or any value you want technically) for r.Rent. in the next process.

Postgresql and comparing to an empty field

It seems that in PostgreSQL, empty_field != 1 (or some other value) is FALSE. If this is true, can somebody tell me how to compare with empty fields?
I have following query, which translates to "select all posts in users group for which one hasn't voted yet:
SELECT p.id, p.body, p.author_id, p.created_at
FROM posts p
LEFT OUTER JOIN votes v ON v.post_id = p.id
WHERE p.group_id = 1
AND v.user_id != 1
and it outputs nothing, even though votes table is empty. Maybe there is something wrong with my query and not with the logic above?
Edit: it seems that changing v.user_id != 1, to v.user_id IS DISTINCT FROM 1, did the job.
From PostgreSQL docs:
For non-null inputs, IS DISTINCT FROM
is the same as the <> operator.
However, when both inputs are null it
will return false, and when just one
input is null it will return true.
If you want to return rows where v.user_id is NULL then you need to handle that specially. One way you can fix it is to write:
AND COALESCE(v.user_id, 0) != 1
Another option is:
AND (v.user_id != 1 OR v.user_id IS NULL)
Edit: spacemonkey is correct that in PostgreSQL you should use IS DISTINCT FROM here.
NULL is a unknown value so it can never equal something. Look into using the COALESCE function.