Linq- A query body must end with a select clause or a group clause in C# - mysql

I am getting error when cross table operation performed as like this.
var rows = from a in db_data.AsEnumerable()
join b in cust_data.AsEnumerable()
on a["SERVICE_ZIP"].ToString().Trim().ToLower() equals b["Zip"].ToString().Trim().ToLower()
where
a["SSS"].ToString().Trim().ToLower() == b["SSS"].ToString().Trim().ToLower() &&
a["ttt"].ToString().Trim().ToLower() == b["ttt"].ToString().Trim().ToLower()
into g
where g.Count() > 0
select a;
DataTable merged;
if (rows.Any())
merged = rows.CopyToDataTable();
else
merged = cust_data.Clone();

Using the into clause allows LINQ comprehension expressions to be chained together, this is very powerful. But each must be a complete comprehension expression.
There is no select or group clause before the into in your code.

Related

Why does `FIELD(joined_table.column, NULL) = 0` not match when the `joined_table` is empty?

FIELD(NULL, NULL) = 0 yields results, also does FIELD(table.column_is_null, NULL) = 0, but not if the string to be compared comes from an empty join table column:
SELECT t.id, FIELD(tj.id, NULL) AS field_zero
FROM task t
LEFT JOIN task tj ON FALSE
WHERE FIELD(tj.id, NULL) = 0
LIMIT 10
This query yields no results, but if i remove the WHERE clause field_zero is zero in all 10 rows:
SELECT t.id, FIELD(tj.id, NULL) AS field_zero
FROM task t
LEFT JOIN task tj ON FALSE
LIMIT 10
According to the docs, FIELD "Returns 0 if str is not found." (see: MySQL 5.7 FIELD documentation)
I searched for bugs of the FIELD function as well as special behaviour on websites documenting FIELD but couldn't find any mention of that issue.
Is this a known bug?
Or do i have a misunderstanding regarding the behaviour of (LEFT) JOIN?
I strongly suspect this is in unknown bug in mysql.
When using COALESCE for the non-string from the empty join table, the query yields results:
SELECT t.id, FIELD(tj.id, NULL) AS field_zero
FROM task t
LEFT JOIN task tj ON FALSE
WHERE FIELD(COALESCE(tj.id), NULL) = 0
LIMIT 10

Odd parentheses behavior in Where clause

SETUP:
MySQL 5.7.14 (Google SQL)
DESCRIPTION:
In the following scenario it appears I am getting some false matches in my where clause where I'm NOT using parentheses. But adding the parentheses DOES yield the correct results.
This Query DOES return results with tsd.StatusID = 3 (wrong):
SELECT
tsee.ID, tsd.StatusID
FROM TSShiftDetails tsd
JOIN TSShiftEmployees tse
ON tse.ShiftID = tsd.ID
JOIN TSShiftEmpEntries tsee
ON tsee.ShiftEmpID = tse.ID
WHERE tsee.CCID IN (4590) OR tsee.CCID LIKE null
AND tsd.StatusID != 3
While this query DOES NOT return results with AND tsd.StatusID = 3 (correct):
SELECT
tsee.ID, tsd.StatusID
FROM TSShiftDetails tsd
JOIN TSShiftEmployees tse
ON tse.ShiftID = tsd.ID
JOIN TSShiftEmpEntries tsee
ON tsee.ShiftEmpID = tse.ID
WHERE (tsee.CCID IN (4590) OR tsee.CCID LIKE null)
AND tsd.StatusID != 3
QUESTION:
While I feel I completely understand why the query WITH the parentheses is working. My question is WHY is the one without parentheses returning records with a StatusID == 3? I would think without any functional ordering of parentheses, the AND tsd.StatusID != 3 clause would be applied to every match regardless of the preceding OR.
What Ya'll think? Am I misunderstanding, or is MySQL behaving inconsistently here?
P.S.
FYI, Yes there is a front end application reason for the need to have the Where clause formatted this way. eg. tsee.CCID IN (4590) as opposed to tsee.CCID =4590
The explanation has nothing to do with LIKE NULL or IN ( ).
Boolean expressions follow an order of operator precedence, just like arithmetic.
In arithmetic, you may remember that multiplication has higher precedence than addition:
A + B * C
Without parentheses, this works exactly like:
A + (B * C)
If you want the addition to be evaluated first, you must use parentheses to override the default operator precedence:
(A + B) * C
Similarly, in boolean expressions, AND has higher precedence than OR.
A OR B AND C
Works like:
A OR (B AND C)
If you want the OR to be evaluated first, you must use parentheses to override the default operator precedence:
(A OR B) AND C
How does this explain what you're seeing?
WHERE tsee.CCID IN (4590) OR tsee.CCID LIKE null
AND tsd.StatusID != 3
This works as if you had done:
WHERE tsee.CCID IN (4590) OR (tsee.CCID LIKE null
AND tsd.StatusID != 3)
So if it finds a row with CCID 4590, that row satisfies the whole WHERE clause, because true OR (anything) is still true.

Optimize derived table in select

I have sql query:
SELECT tsc.Id
FROM TEST.Services tsc,
(
select * from DICT.Change sp
) spc
where tsc.serviceId = spc.service_id
and tsc.PlanId = if(spc.plan_id = -1, tsc.PlanId, spc.plan_id)
and tsc.startDate > GREATEST(spc.StartTime, spc.startDate)
group by tsc.Id;
This query is very, very slow.
Explain:
Can this be optimized? How to rewrite this subquery for another?
What is the point of this query? Why the CROSS JOIN operation? Why do we need to return multiple copies of id column from Services table? And what are we doing with the millions of rows being returned?
Absent a specification, an actual set of requirements for the resultset, we're just guessing at it.
To answer your questions:
Yes, the query could be "optimized" by rewriting it to the resultset that is actually required, and do it much more efficiently than the monstrously hideous SQL in the question.
Some suggestions: ditch the old-school comma syntax for the join operation, and use the JOIN keyword instead.
With no join predicates, it's a "cross" join. Every row matched from one side matched to every row from the right side.) I recommend including the CROSS keyword as an indication to future readers that the absence of an ON clause (or, join predicates in the WHERE clause) is intentional, and not an oversight.
I'd also avoid an inline view, unless there is a specific reason for one.
UPDATE
The query in the question is updated to include some predicates. Based on the updated query, I would write it like this:
SELECT tsc.id
FROM TEST.Services tsc
JOIN DICT.Change spc
ON tsc.serviceid = spc.service_id
AND tsc.startdate > spc.starttime
AND tsc.startdate > spc.starttdate
AND ( tsc.planid = spc.plan_id
OR ( tsc.planid IS NOT NULL AND spc.plan_id = -1 )
)
Ensure that the query is making use of suitable index by looking at the output of EXPLAIN to see the execution plan, in particular, which indexes are being used.
Some notes:
If there are multiple rows from spc that "match" a row from tsc, the query will return duplicate values of tsc.id. (It's not clear why or if we need to return duplicate values. IF we need to count the number of copies of each tsc,id, we could do that in the query, returning distinct values of tsc.id along with a count. If we don't need duplicates, we could return just a distinct list.
GREATEST function will return NULL if any of the arguments are null. If the condition we need is "a > GREATEST(b,c)", we can specify "a > b AND a > c".
Also, this condition:
tsc.PlanId = if(spc.plan_id = -1, tsc.PlanId, spc.plan_id)
can be re-written to return an equivalent result (I'm suspicious about the actual specification, and whether this original condition actually satisfies that adequately. Without example data and sample of expected output, we have to rely on the SQL as the specification, so we honor that in the rewrite.)
If we don't need to return duplicate values of tsc.id, assuming id is unique in TEST.Services, we could also write
SELECT tsc.id
FROM TEST.Services tsc
WHERE EXISTS
( SELECT 1
FROM DICT.Change spc
ON spc.service_id = tsc.serviceid
AND spc.starttime < tsc.startdate
AND spc.starttdate < tsc.startdate
AND ( ( spc.plan_id = tsc.planid )
OR ( spc.plan_id = -1 AND tsc.planid IS NOT NULL )
)
)

Using the right MYSQL JOIN

I'm trying to get all the data from the match table, along with the currently signed up gamers of each type, experienced or not.
Gamers
(PK)Gamer_Id
Gamer_firstName,
Gamer_lastName,
Gamer experience(Y/N)
Gamer_matches
(PK)FK GamerId,
(PK)FK MatchId,
Gamer_score
Match
(PK)Match_Id,
ExperiencedGamers_needed,
InExperiencedGamers_needed
I've tried this query along with many others but it doesn't work, is it a bad join?
SELECT M.MatchId,M.ExperiencedGamers_needed,M.InExperiencedGamers_needed,
(SELECT COUNT(GM.GamerId)
FROM Gamers G, Gamers_matches GM
WHERE G.GamerId = GM.GamerId
AND G.experience = "Y"
AND GM.MatchId = M.MatchId
GROUP BY GM.MatchId)AS ExpertsSignedUp,
(SELECT COUNT(GM.GamerId)
FROM Gamers G, Gamers_matches GM
WHERE G.GamerId = GM.GamerId
AND G.experience = "N"
AND GM.MatchId = M.MatchId
GROUP BY GM.MatchId) AS NovicesSignedUp
FROM MATCHES M
What you've written is called a correlated subquery which forces SQL to re-execute the subquery for each row fetched from Matches. It can be made to work, but it's pretty inefficient. In some complex queries it may be necessary, but not in this case.
I would solve this query this way:
SELECT M.MatchId, M.ExperiencedGamers_needed,M.InExperiencedGamers_needed,
SUM(G.experience = 'Y') AS ExpertsSignedUp,
SUM(G.experience = 'N') AS NovicesSignedUp
FROM MATCHES M
LEFT OUTER JOIN (Gamer_matches GM
INNER JOIN Gamers G ON G.GamerId = GM.GamerId)
ON M.MatchId = GM.MatchId
GROUP BY M.MatchId;
Here it outputs only one row per Match because of the GROUP BY at the end.
There's no subquery to re-execute many times, it's just joining Matches to the respective rows in the other tables once. But I use an outer join in case a Match has zero players of eithe type signed up.
Then instead of using COUNT() I use a trick of MySQL and use SUM() with a boolean expression inside the SUM() function. Boolean expressions in MySQL always return 0 or 1. The SUM() of these is the same as the COUNT() where the expression returns true. This way I can get the "count" of both experts and novices only scanning the Gamers table once.
P.S. MySQL is working in a non-standard way to return 0 or 1 from a boolean expression. Standard ANSI SQL does not support this, nor do many other brands of RDBMS. Standardly, a boolean expression returns a boolean, not an integer.
But you can use a more verbose expression if you need to write standard SQL for portability:
SUM(CASE G.experience WHEN 'Y' THEN 1 WHEN 'N' THEN 0 END) AS ExpertsSignedUp

Convert this SQL statement to LINQ-to-SQL

I have struggled converting this SQL statement to LINQ to SQL VB.Net 9.0. I have used Linqer but no success. Any help would be appreciated
select t.TeeId,
t.DescriptionId,
t.[Description],
t.Rating,
t.Slope,
case when d.TotalHoles <> h.TotalHoles then 0
else 1 end [Status]
from dbo.CourseDescription d
inner join dbo.CourseTees t
on t.DescriptionId = d.DescriptionId
inner join (select TeeId, count(*) as TotalHoles
from dbo.CourseHoles
group by TeeId) h
on h.TeeId = t.TeeId
where d.CourseId = 1
Here's a go at it. I don't do any programming in VB, but I've tried to get the syntax as correct as possible. For simplicity I split it into two queries, but with LINQ to SQL the first doesn't actually result in a query of the DB. It's simply combined with the second. Neither are executed until you enumerate the second query. Add line continuations if and when needed. I don't know if there is a translation to SQL for the ternary operator (there is in C#). If not, material the part before the select, getting both d.TotalHoles and h.TotalHoles, then use LINQ to objects to enumerate through those and construct the status.
dim holes = from h in db.TotalHoles
groupby h.TeeId into g
select TeeId = Key, TotalHoles = g.Count()
dim courses = from d in db.CourseDescription
where d.CourseId = 1
join t in CourseTees on d.DescriptionId equals t.DescriptionId
join h in holes on h.TeeId equals t.TeeId
select t.TeeId,
t.DescriptionId,
t.Description,
t.Rating, t.Slope,
Status = If(d.TotalHoles = h.TotalHoles, 1, 0)