LINQ generating wrong SQL for empty string - sql

I have the following code:
var approver = _context.approver.Where(x => x.ApproverName != "").Select(x => x.ApproverUserId).Distinct();
And the generated SQL is
SELECT DISTINCT "x"."approveruserid"
FROM "approver" "x"
WHERE (("x"."approvername" <> '') OR "x"."approvername" IS NULL )
I'm expecting the SQL should be
SELECT DISTINCT "x"."approveruserid"
FROM "approver" "x"
WHERE (("x"."approvername" <> '') OR "x"."approvername" IS NOT NULL )
So, the generated SQL is missing the NOT clause and this causes to return wrong result. By the way, I'm using Oracle Database. In Oracle, null equals to empty string.
How to fix it?
[UPDATE]: I'm using
var approver = _context.approver.Where(x => x.ApproverName.Length > 0).Select(x => x.ApproverUserId).Distinct();
as a workaround. But I'm open to another suggestion that can generate the SQL properly for empty string checking.

The generated SQL is correct. You are asking for the string to be something other than "", and null != "".
String.IsNullOrEmpty() is not supported by Linq to SQL but your workaround works fine.
Alternatively you can use something like this:
_context.approver.Where(x => (x.ApproverName ?? "" ) != "")

Related

Write SELECT CASE Statement with PostgreSQL pg and Node JS

I am using a RESTful API with Node.js/Express and a PostgreSQL database ( PostgreSQL version is 12.4). I'm not using an ORM just straight SQL. I am trying to create a "SELECT CASE" statement but I keep running into errors. The error messages I am getting are "confirmed_member is not a column". Can anyone see what is wrong with my syntax here:
var query = ['SELECT *, CASE WHEN confirmed = true THEN "confirmed_member" ELSE "pending" END AS "status" FROM members WHERE groupid = $1']
try {
const member = await pool.query(query, [groupid]);
res.status(200).json(member.rows)
} catch (err) {
res.status(400).json({ message: err.message })
}
Note: The query works fine in Valentina DB.
EDIT: In response to answers below, I switched to double quotes because this was the error I was getting in the IDE when I used single quotes
Use single quotes for string literals in SQL. Some flavors of SQL (e.g. SQLite) also accept double quotes, but you should not rely on this behavior.
var query = ["SELECT *, CASE WHEN confirmed = true THEN 'confirmed_member' ELSE 'pending' END AS status FROM members WHERE groupid = $1"];
You need to use single quote for the literals as follows:
SELECT *,
CASE WHEN confirmed = true THEN 'confirmed_member' ELSE 'pending' END AS "status"
FROM members WHERE groupid = $1
For anyone who comes across the same issue: I got it working by enclosing the SQL statement in double quotes and escaping the double quotes for the column name.
var query = ["SELECT *, CASE WHEN confirmed = true THEN 'confirmed_member' ELSE 'pending' END AS \"status\" FROM members WHERE groupid = $1"]

Check if field exists in CosmosDB JSON with SQL - nodeJS

I am using Azure CosmosDB to store documents (JSON).
I am trying to query all documents that contain the field "abc", and not return the documents that do not have the field "abc". For example, return the first object below and not the second
{
"abc": "123"
}
{
"jkl": "098"
}
I am trying to use the following code:
client.queryDocuments(
collectionUrl,
`SELECT r.id, r.authToken.instagram,r.userName FROM root r WHERE r.abc`
)
I assumed the above would check if abc exists similar to if (r.abc) {}
I have tried using WHERE r.abc IS NOT NULL
Thanks in advance
If you want to know if a field exists you should use the IS_DEFINED("FieldName")
If you want to know if the field's value has a value the
FieldName != null or
FieldName <> null (apparently)
I use variations of this in production:
SELECT c.FieldName
FROM c
WHERE IS_DEFINED(c.FieldName)
All you need to do is change your query to
SELECT r.id, r.authToken.instagram,r.userName FROM root r WHERE r.abc != null
or
SELECT r.id, r.authToken.instagram,r.userName FROM root r WHERE r.abc <> null
Both operators work (tested on the Data Explorer)
Add the NOT operator in the SQL query to negate.
SELECT r.id, r.authToken.instagram,r.userName
FROM root r
WHERE NOT IS_DEFINED(r.abc)
to include all entries where the FieldName abc doesn't exist.

Linq.Where-to-SQL on a text field comparing to a list of values

Customer.text is a field in an T-SQL DB (that I do not control and thus may not alter) of type "text".
I'd like to do something like this:
List<string> compare = new List<string>();
compare.Add("one");
compare.Add("two");
var q = from t in customer
where t.text.Contains( compare.First())
select t;
this will work.
But now I'd like to do something like: (!NOT WORKING!)
var q = from t in customer
where compare.Contains( t.text )
select t;
How can I achieve this? Is it even possible?
EDIT: The problem is obviously not exactly clear: A text column in SQL cannot be queried using "=" but only with LIKE. Thus the compare.Contains( t.text ) will result in an error, as it is converted into a query using "=".
What I did not tell - I thought it is irrelevant - is, that I use LINQ-to-ORM (LLBLGen in this case).
What I tried instead:
var q = from t in customer
where compare.Any( x => t.text.Contains(x) )
select t;
Now this did not work also. Currently I'm not at work, but the exception was something with a ConstantExpression not being convertable into a SetExpression.
I hope this gave some clarification.
EDIT2:
Joseph pointed this out to me: PredicateBuilder. It creates an Expression on a given ObjectType.
Now my problem is, that my type is an anonymous type out of multiple joins.
Is there an easy or elegant way to handle this?
Now I might be missing something, but your code looks like it should work. Did you include the namespaces at the top of the file?
using System.Linq;
using System.Linq.Expressions;
You could also rewrite it without the Linq2Sql syntax, like:
var q = customer.Where(c => compare.Contains(c.text));
You could build your query using LinqKit's free predicate builder class. Here is a blog post which describes its use and has a link to the download site.
http://thecodeslinger.wordpress.com/2008/10/28/linqkit-predicatebuildert-goodness/
Below is a code sample from the post
//First get a list of keywords that match the description entered.
string[] parts = txtInclude.Text.Split(new[] {‘ ‘});
string[] noparts = null;
if(txtButNot.Text.Trim().Length > 0)
noparts = txtExclude.Text.Trim().Split(new[] {‘ ‘});
var pred = PredicateBuilder.True<Pet>();
//here is where you would loop through your compare object
parts.ForEach(p => pred = pred.And(pl => pl.description.Contains(p)));
if(noparts != null)
noparts.ForEach(p => pred = pred.And(pl => !pl.description.Contains(p)));
var pets = from s in db.Pets.Where(pred)
select s;
You have to convert the text field to string
var query = from t in dataContext.table
where compare.Contains(t.textField.ToString())
select t;

LINQ Incompatibility Issue with SQL Server 2000

I have a Linq to SQL query that was working just fine with SQL Server 2005 but, I have to deploy the web app with a SQL Server 2000 and, when executing that query, I get his error:
"System.Data.SqlClient.SqlException: The column prefix 't0' does not match with a table name or alias name used in the query."
I have more queries but it doesn't seems to have problems with those.
Now, this is the query:
from warningNotices in DBContext_Analyze.FARs
where warningNotices.FAR_Area_ID == filter.WarningAreaID &&
warningNotices.FAR_Seq == filter.WarningSeq &&
warningNotices.FAR_Year == filter.WarningYear
orderby warningNotices.FAR_Seq ascending
select new Search_Result
{
FAR_Area_ID = warningNotices.FAR_Area_ID,
FAR_Seq = warningNotices.FAR_Seq,
FAR_Year = warningNotices.FAR_Year,
DateTime_Entered = (DateTime)warningNotices.DateTime_Entered == null ? DateTime.MaxValue : (DateTime)warningNotices.DateTime_Entered,
Time_Entered = warningNotices.Time_Entered,
OrigDept = warningNotices.OrigDept,
Part_No = warningNotices.Part_No,
DateTime_Analyzed = (DateTime)warningNotices.DateTime_Analyzed == null ? DateTime.MaxValue : (DateTime)warningNotices.DateTime_Analyzed,
Analyzed_By = warningNotices.Analyzed_By,
MDR_Required = (Char)warningNotices.MDR_Required == null ? Char.MinValue : (Char)warningNotices.MDR_Required,
Resp_Dept = (from FARSympt in DBContext_Analyze.FAR_Symptoms
where FARSympt.FAR_Area_ID == warningNotices.FAR_Area_ID &&
FARSympt.FAR_Year == warningNotices.FAR_Year &&
FARSympt.FAR_Seq == warningNotices.FAR_Seq
select new { FARSympt.Resp_Dept}).FirstOrDefault().Resp_Dept,
Sympt_Desc = (from SymptomsCatalog in DBContext_Analyze.Symptoms
where SymptomsCatalog.symptom_ID == filter.Status_ID
select new {
SymptomsCatalog.Sympt_Desc
}).FirstOrDefault().Sympt_Desc,
Status_ID = warningNotices.Status.HasValue ? warningNotices.Status.Value : 0
};
Previously I had a "Distinc" in the subquery for the Resp_Dept field, but I removed it.
Any ideas? Thanks in advance for your comments =)
This is query I get from the SQL Server profiler:
exec sp_executesql N'SELECT [t0].[FAR_Seq], [t0].[FAR_Year],
(CASE
WHEN ([t0].[DateTime_Entered]) IS NULL THEN #p3
ELSE [t0].[DateTime_Entered]
END) AS [DateTime_Entered], [t0].[Time_Entered], [t0].[OrigDept], [t0].[Part_No],
(CASE
WHEN ([t0].[DateTime_Analyzed]) IS NULL THEN #p4
ELSE [t0].[DateTime_Analyzed]
END) AS [DateTime_Analyzed], [t0].[Analyzed_By],
(CASE
WHEN (UNICODE([t0].[MDR_Required])) IS NULL THEN #p5
ELSE CONVERT(NChar(1),[t0].[MDR_Required])
END) AS [MDR_Required], (
SELECT [t2].[Resp_Dept]
FROM (
**SELECT TOP (1)** [t1].[Resp_Dept]
FROM [dbo].[FAR_Symptoms] AS [t1]
WHERE (UNICODE([t1].[FAR_Area_ID]) = UNICODE([t0].[FAR_Area_ID])) AND ([t1].[FAR_Year] = [t0].[FAR_Year]) AND ([t1].[FAR_Seq]
= [t0].[FAR_Seq])
) AS [t2]
) AS [Resp_Dept], (
SELECT [t4].[Sympt_Desc]
FROM (
**SELECT TOP (1)** [t3].[Sympt_Desc]
FROM [dbo].[Symptoms] AS [t3]
WHERE [t3].[symptom_ID] = #p6
) AS [t4]
) AS [Sympt_Desc], [t0].[FAR_Area_ID],
(CASE
WHEN [t0].[Status] IS NOT NULL THEN [t0].[Status]
ELSE #p7
END) AS [Status_ID]
FROM [dbo].[FARs] AS [t0]
WHERE (UNICODE([t0].[FAR_Area_ID]) = #p0) AND ([t0].[FAR_Seq] = #p1) AND ([t0].[FAR_Year] = #p2)
ORDER BY [t0].[FAR_Seq]',N'#p0 int,#p1 int,#p2 varchar(2),#p3 datetime,#p4 datetime,#p5 nchar(1),#p6 int,#p7
int',#p0=76,#p1=7204,#p2='08',#p3=''9999-12-31 23:59:59:997'',#p4=''9999-12-31 23:59:59:997'',#p5=N' ',#p6=0,#p7=0
The only think that I see there that may not in SQL Server 2000 is the '()' in the "Select top..." but I'm not sure if that is what is causing the problem and, also, I don't know how that could be fixed =S
Thanks again =)
My Linq statement worked on SQL2008 but broke with the exact same error message on SQL2000.
Had a very similar Linq query that worked on both, the only real difference was that before calling .ToList() I called the .OrderBy() clause.
Ex:
var query = from t1 in table1 ...
...;
list = query.OrderBy(o => o.Field).ToList()
Tried the same OrderBy clause on the broken Linq query and it worked!
Has to be a bug?
Do you have the latest Service Pack for Visual Studio and the framework?
I just checked some of my Linq generated SQL and it is using "Top 1" correctly against a SQL Server 2000 database.
after several testing and review the DB, I found that the problem was a legacy table I was working on: that table has "text" type fields. Also, I had to remove some "Distinct" instructions in a nested query I had.
I found this and, after review that, I found that I have to change my queries and that the "Distinct" instruction does not work correctly. As a side note, let me say that the nested queries can also generate unexpected behavior.
So, the real lesson here is that if you need to deploy this against a SQL Server 2000, set an instance of the server and test against it!!! XD
Thanks a lot of your help =)

How to make Linq to SQL translate to a derived column?

I have a table with a 'Wav' column that is of type 'VARBINARY(max)' (storing a wav file) and would like to be able to check if there is a wav from Linq to SQL.
My first approach was to do the following in Linq:
var result = from row in dc.Table
select new { NoWav = row.Wav != null };
The problem with the code above is it will retreive all the binary content to RAM, and this isn't good (slow and memory hungry).
Any idea how to have Linq query to translate into something like bellow in SQL?
SELECT (CASE WHEN Wav IS NULL THEN 1 ELSE 0 END) As NoWav FROM [Update]
Thanks for all the replies. They all make sense. Indeed, Linq should translate the != null correctly, but it didn't seem to effectively do it: running my code was very slow, so somehow my only explaination is that it got the binary data transfered over to the RAM.... but maybe I'm wrong.
I think I found a work around anyway somewhere else on stackoverflow: Create a computed column on a datetime
I ran the following query against my table:
ALTER TABLE [Table]
ADD WavIsNull AS (CASE WHEN [Wav] IS NULL Then (1) ELSE (0) END)
Now I'll update my DBML to reflect that computed column and see how it goes.
Are you sure that this code will retrieve the data to RAM?
I did some testing using LINQPad and the generated SQL was optimized as you suggest:
from c in Categories
select new
{
Description = c.Description != null
}
SELECT
(CASE
WHEN [t0].[description] IS NOT NULL THEN 1
ELSE 0
END) AS [Description]
FROM [Category] AS [t0]
What about this query:
var result = from row in dc.Table where row.Wav == null
select row.PrimaryKey
for a list of keys where your value is null. For listing of null/not null you could do this:
var result = from row in db.Table
select new
{ Key = row.Key, NoWav = (row.Wav == null ? true : false) };
That will generate SQL code similar to this:
SELECT [t0].[WavID] AS [Key],
(CASE
WHEN [t0].[Wav] IS NULL THEN 1
ELSE 0
END) AS [NoWav]
FROM [tblWave] AS [t0]
I'm not clear here, your SQL code is going to return a list of 1s and 0s from your database. Is that what you are looking for? If you have an ID for your record then you could just retrieve that single record with the a condition on the Wav field, null return would indicate no wav, i.e.
var result = from row in dc.Table
where (row.ID == id) && (row.Wav != null)
select new { row.Wav };