question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Incorrect SQL generation in Join statement with subquery

See original GitHub issue

I’ve faced with problem when create large query with subquery.

The query consists of two parts

var vendors = db.DocumentIt
                    .Where(w => w.IdDoc == idDoc)
                    .InnerJoin(db.SprShiPkis,
                        (it, sprShi) => it.Shi == sprShi.Shifr,
                        (it, sprShi) => new { it, sprShi })
                    .Where(w => w.sprShi.IdNumber.HasValue)
                    .InnerJoin(db.VBaseDocuments,
                        (all, whDocs) => all.it.IdBaseDoc == whDocs.IdDoc,
                        (all, whDocs) => new { all.it, all.sprShi, whDocs })
                    .GroupBy(w => w.sprShi.IdNumber)
                    .Select(w => new
                    {
                        IdNumber = w.Key,
                        IdDoc = w.Max(s => s.whDocs.IdDoc)
                    })
                    .LeftJoin(db.VBaseDocuments,
                        (all, doc) => all.IdDoc == doc.IdDoc,
                        (all, doc) => new { all.IdNumber, doc.IdVendor })
                    .LeftJoin(db.VBaseVendors,
                        (all, vnd) => all.IdVendor == vnd.IdVendor,
                        (all, vnd) => new { all, vnd })
                    .Select(w => new
                    {
                        IdNumber = w.all.IdNumber ?? 0,
                        UrAdres = w.vnd.UrAdres ?? string.Empty,
                        INN = w.vnd.INN ?? string.Empty,
                        Name = w.vnd.Naim ?? string.Empty
                    });

When I watch query, generated in this variable i have (as expected)

DECLARE @idDoc Int -- Int32
SET     @idDoc = 14453

SELECT
	Coalesce([all_1].[IdNumber], 0),
	Coalesce([vendor].[UrAdres], N''),
	Coalesce([vendor].[INN], N''),
	Coalesce([vendor].[Name], N'')
FROM
	(
		SELECT
			Max([whDocs].[IdDocument]) as [IdDocument],
			[sprShi].[IdNumber] as [IdNumber]
		FROM
			[dbo].[DocumentIt] [w]
				INNER JOIN [dbo].[SprShiPki] [sprShi] ON [w].[shi] = [sprShi].[shifr]
				INNER JOIN [dbo].[vBaseDocument] [whDocs] ON [w].[IdBaseDocument] = [whDocs].[IdDocument]
		WHERE
			[sprShi].[IdNumber] IS NOT NULL AND [w].[IdDoc] = @idDoc
		GROUP BY
			[sprShi].[IdNumber]
	) [all_1]
		LEFT JOIN [dbo].[vBaseDocument] [doc] ON [all_1].[IdDocument] = [doc].[IdDocument]
		LEFT JOIN [dbo].[vBaseVendor] [vendor] ON [doc].[IdVendor] = [vendor].[IdVendor]

It’s used in other query

var groupedKi = db.Documents
                    .Where(w => w.IdDoc == idDoc)
                    .InnerJoin(db.DocumentIt,
                        (document, it) => document.IdDoс == it.IdDoс,
                        (document, it) => new {document, it})
                    .Where(w => w.it.Shi != null && w.it.Shi.Trim() != string.Empty)
                    .LeftJoin(db.VPrice,
                        (all, price) => all.it.Shi == price.SHI,
                        (all, price) => new {all.document, all.it, price})
                    .LeftJoin(db.SprShiPkis,
                        (all, sprShiPki) => all.it.Shi == sprShiPki.Shifr,
                        (all, sprShiPki) => new {all.document, all.it, all.price, sprShiPki})
                    .LeftJoin(vendors,
                        (all, vendor) => all.sprShiPki.IdNumber == vendor.IdNumber,
                        (all, vendor) => new { all.document, all.it, all.price, all.sprShiPki, vendor })
                    .LeftJoin(db.SprNamePkis,
                        (all, sprNamePki) => all.sprShiPki.IdNumber == sprNamePki.IdNumber,
                        (all, sprNamePki) => new { all.document, all.it, all.price, all.sprShiPki, all.vendor, sprNamePki })
                    .LeftJoin(db.Resources,
                        (all, res) => all.it.Shi == res.Shifr,
                        (all, res) => new {all.document, all.it, all.price, all.sprShiPki, all.vendor, all.sprNamePki, res})
                    .LeftJoin(db.GrKis,
                        (all, grKi) => Convert.ToInt32(all.res.Grp) == grKi.GP,
                        (all, grKi) => new {all.document, all.it, all.price, all.sprShiPki, all.vendor, all.sprNamePki, all.res, grKi})
                    .LeftJoin(db.GrPKI1.Where(s => s.IdDoc == idDoc),
                        (all, grk1) => Convert.ToInt32(all.res.Grp) == grk1.GP,
                        (all, grk1) => new {all.document, all.it, all.price, all.sprShiPki, all.vendor, all.sprNamePki, all.res, all.grKi, grk1, Price = Convert.ToDouble(all.it.Cn)})
                    .GroupBy(w => new
                    {
                        w.price.GRP,
                        w.res.PGrp,
                        w.res.KName,
                        w.it.Cn,
                        w.vendor.Name,
                        w.vendor.INN,
                        w.vendor.UrAdres,
                        w.grk1.Koef,
                        w.grKi.GrName,
                        DocName = w.document.Name,
                        w.document.Nds,
                        w.document.Tzr,
                        w.document.Vozvr,
                        w.sprNamePki.Description,
                        w.sprNamePki.Name,
                        w.it.Npr,
                        w.it.Nt,
                        w.res.Grp,
                        w.sprNamePki.Import,
                        GP = w.grk1.GP,
                        w.Price
                    })
                    .Select(all => new RepDoc
                    {
                        Grp = Convert.ToInt32(all.Key.Grp),
                        PGrp = all.Key.PGrp,
                        Shi = string.Empty,
                        MatName = all.Key.Nameen,
                        Description = all.Key.Description,
                        KName = all.Key.KName,
                        Kol = all.Sum(w => w.it.Kol),
                        Price = all.Key.Price,
                        CdDocument = null,
                        VdNom = string.Empty,
                        NPARTNER = all.Key.Name,
                        INN = all.Key.INN,
                        UrAdres = all.Key.UrAdres,
                        Nch = all.Key.Npr + " " + all.Key.Nt,
                        NameDoc = string.Empty,
                        Nds = all.Key.Nds ?? 1,
                        Tzr = all.Key.Tzr ?? 0,
                        Vozvr = all.Key.Vozvr ?? 0,
                        CdUser = cdUser,
                        DescriptionGrp = all.Key.Description,
                        Import = all.Key.Import == 1,
                        FormGr = all.Key.GP
                    });

This generates the following SQL Statement

...
LEFT JOIN [dbo].[SprShiPki] [sprShiPki] ON [it].[shi] = [sprShiPki].[shifr]
LEFT JOIN (
	SELECT
		Coalesce([vendor].[Name], N'') as [c1],
		Coalesce([vendor].[INN], N'') as [c2],
		Coalesce([vendor].[UrAdres], N'') as [c3]
	FROM
		(
			SELECT
				Max([whDocs].[IdDocument]) as [IdDocument],
				[sprShi].[IdNumber] as [IdNumber]
			FROM
				[dbo].[DocumentIt] [w_1]
					INNER JOIN [dbo].[SprShiPki] [sprShi] ON [w_1].[shi] = [sprShi].[shifr]
					INNER JOIN [dbo].[vBaseDocument] [whDocs] ON [w_1].[IdBaseDocument] = [whDocs].[IdDocument]
			WHERE
				[sprShi].[IdNumber] IS NOT NULL AND [w_1].[IdDoc] = @idDoc0
			GROUP BY
				[sprShi].[IdNumber]
		) [all_1]
			LEFT JOIN [dbo].[vBaseDocument] [doc] ON [all_1].[IdDocument] = [doc].[IdDocument]
			LEFT JOIN [dbo].[vBaseVendor] [vendor] ON [doc].[IdVendor] = [vendor].[IdVendor]
) [t1] ON ([sprShiPki].[IdNumber] IS NULL AND Coalesce([all_1].[IdNumber], 0) IS NULL OR [sprShiPki].[IdNumber] = Coalesce([all_1].[IdNumber], 0))
LEFT JOIN [dbo].[SprNaimPki] [sprNaimPki] ON [sprShiPki].[IdNumber] = [sprNaimPki].[IdNumber]
...

but I’ve expected

...
LEFT JOIN [dbo].[SprShiPki] [sprShiPki] ON [it].[shi] = [sprShiPki].[shifr]
LEFT JOIN (
	SELECT
		Coalesce([all_1].[IdNumber], 0) as [IdNumber],
		Coalesce([vendor].[Name], N'') as [c1],
		Coalesce([vendor].[INN], N'') as [c2],
		Coalesce([vendor].[UrAdres], N'') as [c3]
	FROM
		(
			SELECT
				Max([whDocs].[IdDocument]) as [IdDocument],
				[sprShi].[IdNumber] as [IdNumber]
			FROM
				[dbo].[DocumentIt] [w_1]
					INNER JOIN [dbo].[SprShiPki] [sprShi] ON [w_1].[shi] = [sprShi].[shifr]
					INNER JOIN [dbo].[vBaseDocument] [whDocs] ON [w_1].[IdBaseDocument] = [whDocs].[IdDocument]
			WHERE
				[sprShi].[IdNumber] IS NOT NULL AND [w_1].[IdDoc] = @idDoc0
			GROUP BY
				[sprShi].[IdNumber]
		) [all_1]
			LEFT JOIN [dbo].[vBaseDocument] [doc] ON [all_1].[IdDocument] = [doc].[IdDocument]
			LEFT JOIN [dbo].[vBaseVendor] [vendor] ON [doc].[IdVendor] = [vendor].[IdVendor]
) [t1] ON ([sprShiPki].[IdNumber] IS NULL AND [t1].[IdNumber] IS NULL OR [sprShiPki].[IdNumber] =  [t1].[IdNumber])
LEFT JOIN [dbo].[SprNaimPki] [sprNaimPki] ON [sprShiPki].[IdNumber] = [sprNaimPki].[IdNumber]

[all_1] used out of scope instead [t1] in Join statement.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:8 (6 by maintainers)

github_iconTop GitHub Comments

2reactions
Brainscommented, Jun 15, 2019

you have shown very simple query, not comparable to original post.

agree, it’s true

If you do not use query syntax - you have to create a lot of anonymous classes and projections by the hands.

with F# I just use tuples, but agree for C# cases (they are most)

Also such queries are really hard to refactor.

can’t agree, however here I am talking only about LINQ to Objects usages, maybe LINQ to SQL differs

Just compare the same query above and below from this issue #1736

agree for this case totally

C# compiler do a lot of dirty work for you. When you have to move join up or down in fluent syntax - it is a pain.

not sure about pain, will try to move in future, maybe you are right

Conclusion For my simplest queries fluent is not so bad, but for bigger ones it is

0reactions
sdanylivcommented, Jun 24, 2019

Reproduced, thanks. Trying to fix.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Incorrect Syntax Left Join subquery with aggregation
I'm trying to run the following query through SQL Server. I keep getting a incorrect syntax error near',' but I can't figure out...
Read more >
Subqueries (SQL Server)
A subquery is a query that is nested inside a SELECT , INSERT , UPDATE , or DELETE statement, or inside another subquery....
Read more >
"All joins can be rewritten to sub queries", is this statement ...
I would say the statement is false, though it's difficult to prove a negative. I don't believe a CROSS JOIN could be done...
Read more >
Error when using UNION and correlated subquery with ...
I am trying to UNION some statements together. One statement uses a correlated subquery that contains an ORDER BY CLAUSE and when I...
Read more >
Writing Subqueries in SQL
This lesson of the SQL tutorial for data analysis covers using subqueries in SQL with aggregate functions, conditional logic, and joins.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found