Issue With Select Statement - c#

I am trying to select the top 1 of this select query then order DESC, every way I try, it doesn't seem to work. Here is my code:
SELECT '$' + CONVERT(VARCHAR(50),
CONVERT(MONEY, COALESCE(([amount]), 0)),
1) AS [Total]
FROM [myTable] a
left join [mySecondTable] b on a.[ID] = b.[ID]
left join [myThirdTable c on c.[myNumber] = b.[myNumber]
WHERE c.[myName] = 'me'
If I wanted to select top 1 amount and then order by amount with SELECT TOP 1 and ORDER By [amount] DESC, where would I put them exactly? Or this that even the correct way to do this?

Your ORDER BY will go at the end, and top 1 at the beginning.
SELECT top 1 '$' + CONVERT(VARCHAR(50),
CONVERT(MONEY, COALESCE(SUM([amount]), 0)),
1) AS [Total]
FROM [myTable] a
left join [mySecondTable] b on a.[ID] = b.[ID]
left join [myThirdTable c on c.[myNumber] = b.[myNumber]
WHERE c.[myName] = 'me'
order by [AMOUNT] DESC

Related

How to force delete COALESCE function in query. C# EntityFramework 7.0.2 LINQ

Ok, I have such SQL code:
DECLARE #documentId INT = 8
SELECT
i.[status] AS [status],
i.[barcode] AS [barcode],
i.[containerId] AS [containerTypeId],
(
SUM(ISNULL(lp.[Weight], 0) * il.[factCount]) +
ISNULL(lpt.[Weight], 0)
) AS [weight],
i.[comment] AS [comment]
FROM [Items] AS i WITH(NOLOCK)
LEFT JOIN [dbo].[ItemsLines] AS il WITH(NOLOCK) ON i.[id] = il.[itemsId]
LEFT JOIN [dbo].[LagerOptions] AS lp WITH(NOLOCK) ON lp.[lagerId] = il.[lagerId]
LEFT JOIN [dbo].[LagerOptions] AS lpt WITH(NOLOCK) ON lpt.[lagerId] = i.[containerId]
WHERE #documentId = i.[documentId]
GROUP BY i.[status], i.[barcode], i.[containerId], i.[comment], lpt.[Weight]
The most similar code I've written in LINQ is:
var lots = await (
from i in _dbContext.Items
join lpt in _dbContext.LagerOptions on i.ContainerId equals lpt.LagerId into lptTable
from lpt in lptTable.DefaultIfEmpty()
// The sum of all lagers for current lot
let lotWeight = (
from il in _dbContext.ItemsLines
join lp in _dbContext.LagerOptions on il.LagerId equals lp.LagerId into lpTable
from lp in lpTable.DefaultIfEmpty()
where il.ItemsId == i.Id
select (il.FactCount * lp.Weight.GetValueOrDefault(0))
).Sum()
where i.DocumentsId == documentId
select new
{
Status = i.Status,
Barcode = i.Barcode,
ContainerTypeId = i.ContainerId,
// total weight with container Weight
Weight = lotWeight + lpt.Weight.GetValueOrDefault(0),
//
Comment = i.Comment
}
).ToListAsync();
For SQL query the results can contain empty lots or lots with null-weight lagers (problem lagers) that makes "Weight" field of lot is equal NULL that helps detect problem lots.
But when I check the C# LINQ code EntityFramework create a COALESCE() function over SUM() function
and the query converted to SQL looks like this:
SELECT [t].[status] AS [Status], [t].[barcode] AS [Barcode], [t].[containerId] AS [ContainerTypeId], (
SELECT COALESCE(SUM([t0].[factCount] * COALESCE([l0].[Brutto], 0.0)), 0.0)
FROM [dbo].[ItemsLines] AS [t0]
LEFT JOIN [dbo].[LagerOptions] AS [l0] ON [t0].[lagerId] = [l0].[lagerId]
WHERE [t0].[itemsId] = [t].[id]) + COALESCE([l].[weight], 0.0) AS [Weight], [t].[comment] AS [Comment]
FROM [dbo].[Items] AS [t]
LEFT JOIN [dbo].[LagerOptions] AS [l] ON [t].[containerId] = [l].[lagerId]
WHERE [t].[documentId] = #__documentId_0
As a result, the weight of the problem lot will be equal to the container weight of this lot.
I can solve the problem with crutch methods, but I'm sure that there is a simple solution, which, unfortunately, I did not find.
I tryed to add different checks on null and rewrite the query for different JOIN patterns, but the main problem - EntityFramework create a COALESCE() function over SUM() function. And I don't know how to fix it in root. I work with C# EF approximately 1 month. EF 7.0.2
Help me, please.
!!EDITED
Correct LINQ query looks like this (Thank, Svyatoslav Danyliv):
var query =
from i in _dbContext.Items
join il in _dbContext.ItemsLines on i.Id equals il.ItemsId into ilj
from il in ilj.DefaultIfEmpty()
join lp in _dbContext.LagerOptions on il.LagerId equals lp.LagerId into lpj
from lp in lpj.DefaultIfEmpty()
join lpt in _dbContext.LagerOptions on i.ContainerId equals lpt.LagerId into lptj
from lpt in lptj.DefaultIfEmpty()
where i.DocumentsId == documentId
group new { lp, il, lpt } by new { i.Status, i.Barcode, i.ContainerId, i.Comment, lpt.Weight } into g
select new
{
g.Key.Status,
g.Key.Barcode,
ContainerTypeId = g.Key.ContainerId,
Weight = g.Sum(x => ((decimal?)x.lp.Weight) ?? 0 * x.il.FactCount) + g.Key.Weight ?? 0
g.Key.Comment,
};
But the query converted to SQL looks like this:
SELECT
[t].[status] AS [Status],
[t].[barcode] AS [Barcode],
[t].[containerId] AS [ContainerTypeId],
COALESCE(SUM(COALESCE([l].[weight], 0.0) * [t0].[factCount])), 0.0) +
COALESCE([l0].[weight], 0.0) AS [Weight],
[t].[comment] AS [Comment]
FROM [dbo].[Items] AS [t]
LEFT JOIN [dbo].[ItemsLines] AS [t0] ON [t].[id] = [t0].[itemsId]
LEFT JOIN [dbo].[LagerOptions] AS [l] ON [t0].[lagerId] = [l].[lagerId]
LEFT JOIN [dbo].[LagerOptions] AS [l0] ON [t].[containerId] = [l0].[lagerId]
WHERE [t].[documentsId] = #__documentId_0
GROUP BY [t].[status], [t].[barcode], [t].[containerId], [t].[comment], [l0].[weight]
EntityFramework create a COALESCE() function over SUM() function.
How to remove this?
This should equivalent LINQ query to your SQL. I do not understand why instead of grouping you have forced LINQ Translator to generate another query.
var query =
from i in _dbContext.Items
join il in _dbContext.ItemsLines on i.Id equals il.ItemsId into ilj
from il in ilj.DefaultIfEmpty()
join lp in _dbContext.LagerOptions on il.LagerId equals lp.LagerId into lpj
from lp in lpj.DefaultIfEmpty()
join lpt in _dbContext.LagerOptions on i.ContainerId equals lpt.LagerId into lptj
from lpt in lptj.DefaultIfEmpty()
where i.DocumentsId == documentId
group new { lp, il, lpt } by new { i.Status, i.Barcode, i.ContainerId, i.Comment, lpt.Weight } into g
select new
{
g.Key.Status,
g.Key.Barcode,
ContainerTypeId = g.Key.ContainerId,
Weight = g.Sum(x => ((double?)x.lp.Weight) ?? 0 * x.il.FactCount) + g.Key.Weight ?? 0
g.Key.Comment,
};

Reading the day for the current month SQL

This is my current query that works, but I still need days to print out for the whole month starting 2018-05-01, not to skip, is this possible in a sql?
DECLARE #MinDate DATE = DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())-1, 0) ,
#MaxDate DATE = DATEADD(MONTH, DATEDIFF(MONTH, -1, GETDATE())-1, -1);
SELECT TOP (DATEDIFF(DAY, #MinDate, #MaxDate) + 1)
Date = DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, #MinDate) INTO #MYCALENDAR FROM sys.all_objects a CROSS JOIN sys.all_objects b;
SELECT
a.LPE_Pensum,
DATEPART(DAY, CAL.[Date]) AS Tag ,
LEFT(datename(WEEKDAY, CAL.[Date] ),3) AS Datum,
CAL.[Date],
p.ZPZ_Von,
p.ZPZ_Bis FROM
#MYCALENDAR CAL
LEFT JOIN Z_PRAESENZZEIT AS p ON CONVERT(DATE, p.ZPZ_Datum) = CONVERT(DATE, CAL.[Date])
LEFT JOIN A_PERSONAL AS a ON a.LPE_ID = p.ZPZ_LPE_ID
LEFT JOIN A_Arbeitszeitplan AS r on r.LPE_AbteilungID = a.LPE_AbteilungID
LEFT JOIN A_Abteilung AS b ON b.LPE_AbteilungID = r.LPE_AbteilungID WHERE a.LPE_ID=13
and this is the result of a query:
enter image description here
Thanks for your help
You want to scan a particular range of dates, lets say previous month:
DECLARE #MinDate DATE = DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())-1, 0) , -1st day prev month
#MaxDate DATE = DATEADD(MONTH, DATEDIFF(MONTH, -1, GETDATE())-1, -1); -- last day prev month
Now what you need is a calendar table to store your dates:
SELECT TOP (DATEDIFF(DAY, #MinDate, #MaxDate) + 1)
Date = DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, #MinDate)
INTO #MYCALENDAR
FROM sys.all_objects a
CROSS JOIN sys.all_objects b;
We can use our new #MYCALENDAR as baseline for our query:
SELECT
a.LPE_Pensum,
DATEPART(DAY, CAL.[Date]) AS Tag ,
LEFT(datename(WEEKDAY, CAL.[Date] ),3) AS Datum,
CAL.[Date],
p.ZPZ_Von,
p.ZPZ_Bis
FROM
#MYCALENDAR CAL
LEFT JOIN Z_PRAESENZZEIT AS p ON CONVERT(DATE, p.ZPZ_Datum) = CONVERT(DATE, CAL.[Date])
LEFT JOIN A_PERSONAL AS a ON a.LPE_ID = p.ZPZ_LPE_ID
LEFT JOIN A_Arbeitszeitplan AS r on r.LPE_AbteilungID = a.LPE_AbteilungID
LEFT JOIN A_Abteilung AS b ON b.LPE_AbteilungID = r.LPE_AbteilungID
WHERE
a.LPE_ID=13
you may have to change something in your join clauses but, basically, this is how i would proceed.
First of all, try to indent your query, it's impossible to read it that way. Second, you can create a dates table with all the days you are interested in. Search in internet for date dimensions, they will fit very well with your need. And finally, you must left join your query with this table, in order to have a way to see all the days not present in your data.
It would be something like this:
SELECT
a.LPE_Pensum,
dd.[DAY] AS Tag ,
LEFT(datename(WEEKDAY, p.ZPZ_Datum ),3) AS Datum,
p.ZPZ_Datum,p.ZPZ_Von,
p.ZPZ_Bis
FROM [DATE_DIM] dd
LEFT JOIN Z_PRAESENZZEIT AS p
ON dd.[DATE]=DATEPART(DAY, p.ZPZ_Datum)
LEFT JOIN A_PERSONAL AS a
ON a.LPE_ID = p.ZPZ_LPE_ID
AND a.LPE_ID=13
LEFT JOIN A_Arbeitszeitplan AS r
on r.LPE_AbteilungID = a.LPE_AbteilungID
LEFT JOIN A_Abteilung AS b
ON b.LPE_AbteilungID = r.LPE_AbteilungID
WHERE dd.[YEAR]=#YearInterestedIn
The dd.[YEAR]=#YearInterestedIn must be replaced by the range you are interested in your study
You need to generate the days for the current month. Assuming you have some rows in your database, then you can use left join to bring in the dates:
SELECT a.LPE_Pensum, d.dte AS Tag ,
LEFT(datename(WEEKDAY, d.dte),3) AS Datum,
p.ZPZ_Datum, p.ZPZ_Von, p.ZPZ_Bis
FROM (SELECT DISTINCT CAST(p.ZPZ_Datum as date) as dte
FROM Z_PRAESENZZEIT p
WHERE ZPZ_Datum >= datefromparts(year(p.ZPZ_Datum), month(p.ZPZ_Datum), 1) AND
ZPZ_Datum >= dateadd(month, 1, datefromparts(year(p.ZPZ_Datum), month(p.ZPZ_Datum), 1))
) d LEFT JOIN
(A_PERSONAL a JOIN
Z_PRAESENZZEIT p
ON a.LPE_ID = p.ZPZ_LPE_ID
)
ON p.ZPZ_Datum >= d.dte AND p.ZPZ_Datum < DATEADD(day, 1, d.dte) LEFT JOIN
A_Arbeitszeitplan r
ON r.LPE_AbteilungID = a.LPE_AbteilungID
A_Abteilung b
ON b.LPE_AbteilungID = r.LPE_AbteilungID
WHERE a.LPE_ID = 13;
You can generate the dates in a different fashion if necessary.

How does DefaultIfEmpty() imply left outer join?

How does this:
from c in Contacts
join a in Addresses
on c.Address_ID equals a.Address_ID
into Temp
from d in Temp.DefaultIfEmpty()
where c.First_Name.ToUpper().Contains("Pin".ToUpper())
select new { id = c.Contact_ID, value = (c.First_Name??"") + " " + (c.Last_Name??"") + " " + (c.Company_Name??""), FirstName = c.First_Name, LastName = c.Last_Name, AddressFull = d.Address_Full, Phone = c.Phone, Email = c.Email, CompanyName = c.Company_Name }
translate to this (using LinqPad)?
SELECT [t0].[Contact_ID] AS [id], ((((COALESCE([t0].[First_Name],#p1)) + #p2) + (COALESCE([t0].[Last_Name],#p3))) + #p4) + (COALESCE([t0].[Company_Name],#p5)) AS [value], [t0].[First_Name] AS [FirstName], [t0].[Last_Name] AS [LastName], [t1].[Address_Full] AS [AddressFull], [t0].[Phone], [t0].[Email], [t0].[Company_Name] AS [CompanyName]
FROM [Contact] AS [t0]
LEFT OUTER JOIN [Address] AS [t1] ON [t0].[Address_ID] = ([t1].[Address_ID])
WHERE UPPER([t0].[First_Name]) LIKE #p0
It seems that Temp.DefaultIfEmpty() == LEFT OUTER JOIN
What's the reasoning behind this syntax? Can someone please eloquently explain why?
This is not a magic incantation. You get the same semantics with pure LINQ to Objects. The join into is a left join already. It puts all matching items into a collection. There can be zero items or multiple.
from d in Temp.DefaultIfEmpty() would be an inner join because if there were no matching items we would drop the outer row. DefaultIfEmpty can now be used to add a "dummy null" to make this a left join.
This whole pattern is a little awkward but there's logic behind it.

SQL to Linq: RIGHT JOIN in LINQ

anybody can help me to convert some sql query whit right join like this to linq ?
SELECT dbo.FinnTrans.SanadID, dbo.FinnTrans.Date, dbo.FinnAccount.ID AS AccID,
dbo.FinnAccount.FullId, dbo.FinnAccount.Name, SUM(dbo.FinnTrans.Debit) AS TotalDebit,
SUM(dbo.FinnTrans.Credit) AS TotalCredit
FROM dbo.FinnAccount AS FinnAccount_1 LEFT OUTER JOIN
dbo.FinnAccount ON FinnAccount_1.ParentId = dbo.FinnAccount.ID RIGHT OUTER JOIN
dbo.FinnTrans LEFT OUTER JOIN
dbo.FinnAccount AS FinnAccount_2 ON dbo.FinnTrans.AccID = FinnAccount_2.ID ON
FinnAccount_1.ID = FinnAccount_2.ParentId
WHERE (dbo.FinnTrans.FPID = 7) AND (FinnAccount_2.AccLevel = 3)
GROUP BY dbo.FinnTrans.SanadID, dbo.FinnTrans.Date, dbo.FinnAccount.ID,
dbo.FinnAccount.Name, dbo.FinnAccount.FullId
HAVING (dbo.FinnTrans.SanadID = 1)
You can look here: http://www.hookedonlinq.com/OuterJoinSample.ashx as an example of the left outer join. And you can always swap tables to get either left or right
I've taken the liberty of beatifying your TSQL a little.
The last two join conditions appear malformed to me so this TSQL can not be parsed.
SELECT
[t].SanadID
, [t].Date
, [a].ID [AccID]
, [a].FullId
, [a].Name
, SUM([t].Debit) [TotalDebit]
, SUM([t].Credit) [TotalCredit]
FROM
dbo.FinnAccount [a1]
LEFT OUTER JOIN
dbo.FinnAccount [a]
ON [a1].ParentId = [a].ID
RIGHT OUTER JOIN
dbo.FinnTrans [t]
LEFT OUTER JOIN
dbo.FinnAccount [a2]
ON [a].AccID = [a2].ID
ON [a1].ID = [a2].ParentId
WHERE
[t].FPID = 7
AND
[a2].AccLevel = 3
GROUP BY
[t].SanadID
, [t].Date
, [a].ID
, [a].Name
, [a].FullId
HAVING
[t].SanadID = 1

Could this be converted to LINQ?

I have a reasonably long SQL query that I need to run in a .Net application. I can make it a stored procedure but I'd like to avoid it if possible (given that I may have a high number of queries in this app).
With this in mind, could something like the following be converted to LINQ or is it too detailed?
-- Compare current period to historical data
select Name ,
avg(TimeProcessing + TimeRendering + TimeDataRetrieval) / 1000 as 'Current Month' ,
isnull(count(TimeProcessing), 0) as 'Sample' ,
min(l2.[Avg_Exec_Time_Previous_Month]) as 'Previous Month' ,
isnull(min(l2.[Executions_Last_Month]), 0) as 'Sample' ,
min(l3.[Avg_Exec_Time_Two_Months_Ago]) as 'Two Months ago' ,
isnull(min(l3.[Executions_Two_Months_Ago]), 0) as 'Sample'
from marlin.report_execution_log l
inner join marlin.report_catalog c on l.ReportID = c.ItemID
left outer join (
select
l2.ReportID ,
(
avg(l2.TimeProcessing + l2.TimeRendering
+ l2.TimeDataRetrieval) / 1000
) as 'Avg_Exec_Time_Previous_Month' ,
count(l2.TimeProcessing) as 'Executions_Last_Month'
from
marlin.report_execution_log l2
where
TimeEnd between dateadd(MONTH, -2, getdate())
and dateadd(MONTH, -1, getdate())
group by
l2.ReportID
) l2 on l.ReportID = l2.ReportID
left outer join (
select
l3.ReportID ,
(
avg(l3.TimeProcessing + l3.TimeRendering + l3.TimeDataRetrieval) / 1000
) as 'Avg_Exec_Time_Two_Months_Ago' ,
count(l3.TimeProcessing) as 'Executions_Two_Months_Ago'
from
marlin.report_execution_log l3
where
TimeEnd between dateadd(MONTH, -3, getdate())
and dateadd(MONTH, -2, getdate())
group by
l3.ReportID
) l3 on l.ReportID = l3.ReportID
group by l.ReportID ,
Name
order by 2 desc
there are many tools /convertor are available on the internet. you can use this tools
why not you try Sql to Linq
LinqPad

Categories

Resources