Could this be converted to LINQ? - c#

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

Related

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.

Output transactions that exceed certain amount within 3 days

In a month, seperate by AccountNo, all transaction that exceeds 10,000 amount within 3 days must be outputted.
This is a sample table:
AccountNo-----Date------------Amount
1-------------5/1/17----------8000
1-------------5/3/17----------1000
1-------------5/4/17----------1000
1-------------5/6/17----------1000
2-------------5/7/17----------3000
2-------------5/10/17---------2000
2-------------5/13/17---------2000
2-------------5/13/17---------3000
3-------------5/14/17---------3000
3-------------5/15/17---------3000
3-------------5/16/17---------9000
4-------------5/17/17---------1000
5-------------5/18/17---------1000
5-------------5/19/17---------1000
5-------------5/20/17---------1000
The result must be:
AccountNo-----Date------------Amount
1-------------5/1/17----------8000
1-------------5/3/17----------1000
1-------------5/4/17----------1000
2-------------5/7/17----------3000
2-------------5/10/17---------2000
2-------------5/13/17---------2000
2-------------5/13/17---------3000
3-------------5/14/17---------3000
3-------------5/15/17---------3000
3-------------5/16/17---------9000
There is a code given to me, but it's not completely working yet.
Select A.*
From YourTable A
Cross Apply (
Select RT1 = sum(case when [Date] <= B2.TstDate then [Amount] else 0 end)
,RT2 = sum(case when [Date] >= B2.TstDate then [Amount] else 0 end)
From YourTable B1
Cross Join (Select TstDate=A.[Date]) B2
Where [Date] between DateAdd(DAY,-2,A.[Date]) and DateAdd(DAY,2,A.[Date])
and Year([Date])=Year(TstDate)
and Month([Date])=Month(TstDate)
) B
Where RT1>=10000 or RT2>=10000
Common table expression: TransInfo
TransInfo is a table with account, year, month, day, amount
The main query:
The [Tmiddle] query adds a row_number based on amount per day per month per accountno
The [Tmiddle] is joined again with TransInfo to limit the results to top 3 of a month AS [Touter] where the top 3 is >= 10.000
The outer most query combines the result with a table again to gain the complete transaction information again
In short:
Filter data on top 3 amounts per day per month per year per account
Check if sum of amount >= 10.000
Show results
Query:
WITH [TransInfo] ([AccountNo], [Year], [Month], [Day], [Amount], [Rownumber])
AS
(
SELECT [AccountNo]
,[Year]
,[Month]
,[Day]
,[Amount]
,ROW_NUMBER() OVER
(
PARTITION BY [AccountNo],
[Year],
[Month]
ORDER BY [Amount] DESC
) AS [Rownumber]
FROM
(
SELECT [AccountNo]
,DATEPART(YEAR, [Date]) AS [Year]
,DATEPART(MONTH, [Date]) AS [Month]
,DATEPART(DAY, [Date]) AS [Day]
,SUM([Amount]) AS [Amount]
FROM [Test].[dbo].[Data]
GROUP BY [AccountNo],
DATEPART(MONTH, [Date]),
DATEPART(YEAR, [Date]),
DATEPART(DAY, [Date])
) AS [Tinner]
)
SELECT [Data].[AccountNo]
,[Data].[Date]
,[Data].[Amount]
FROM [Test].[dbo].[Data]
INNER JOIN
(
SELECT [TransInfo].[AccountNo]
,[TransInfo].[Year]
,[TransInfo].[Month]
,[TransInfo].[Day]
,[TransInfo].[Amount]
FROM [TransInfo]
INNER JOIN
(
SELECT [AccountNo]
,[Year]
,[Month]
FROM [TransInfo]
WHERE [TransInfo].[Rownumber] <= 3
GROUP BY [TransInfo].[AccountNo],
[TransInfo].[Year],
[TransInfo].[Month]
HAVING SUM ([TransInfo].[Amount]) >= 10000
) AS [Tmiddle]
ON [Tmiddle].[AccountNo] = [TransInfo].[AccountNo]
AND [Tmiddle].[Year] = [TransInfo].[Year]
AND [Tmiddle].[Month] = [TransInfo].[Month]
WHERE [TransInfo].[Rownumber] <= 3
) AS [Touter]
ON [Data].[AccountNo] = [TOuter].[AccountNo]
AND DATEPART(YEAR, [Data].[Date]) = [TOuter].[Year]
AND DATEPART(MONTH, [Data].[Date]) = [TOuter].[Month]
AND DATEPART(DAY, [Data].[Date]) = [TOuter].[Day]
Result: Left is query result, right is complete table
Does this work as expected? You may need to change the 2's to 3's depending on what you mean by 'within 3 days'.
SELECT DISTINCT C.*
FROM YourTable C
INNER JOIN (
SELECT a.AccountNo, a.Date
FROM YourTable a
INNER JOIN YourTable b
ON a.AccountNo = b.AccountNo
AND DATEADD(DAY, 2, a.Date) <= b.Date AND b.Date >= a.Date
GROUP BY a.AccountNo, a.Date
HAVING SUM(b.Amount) > 10000
) d
ON C.AccountNo = d.AccountNo
AND DATEADD(DAY, 2, D.Date) <= C.Date AND C.Date >= D.Date

how to compare a string delimited string to a column value in sql without considering sequence

How to compare a string delimited string to a column value in sql without considering sequence?
Suppose I have a value in sql column [fruits] - mango, apple, cherry... I have list in asp.net C# cherry, mango, apple... I want to write sql query such that it can match sql table without order.
I suggest that you look at the fabulous answers in this SO question
How to split a comma-separated value to columns
That said, your solution should be pass each column which contains words to this function and then store it in a table along with a column ID.
So "mango,apple,cherry" becomes a table with values
ColdID Value
_______________
1 mango
1 apple
1 cherry
Now order the tables by ColID ASC, Value ASC and compare both the tables.
This should do it.
DECLARE #str NVARCHAR(MAX)
, #Delim NVARCHAR(255)
SELECT #str = 'cherry,mango,peach,apple'
SELECT #Delim = ','
CREATE TABLE #Fruits ( Fruit VARCHAR(255) )
INSERT INTO #Fruits
( Fruit )
VALUES ( 'cherry' ),
( 'Mango' ),
( 'Apple' ) ,
( 'Banana' )
;WITH lv0 AS (SELECT 0 g UNION ALL SELECT 0)
,lv1 AS (SELECT 0 g FROM lv0 a CROSS JOIN lv0 b) -- 4
,lv2 AS (SELECT 0 g FROM lv1 a CROSS JOIN lv1 b) -- 16
,lv3 AS (SELECT 0 g FROM lv2 a CROSS JOIN lv2 b) -- 256
,lv4 AS (SELECT 0 g FROM lv3 a CROSS JOIN lv3 b) -- 65,536
,lv5 AS (SELECT 0 g FROM lv4 a CROSS JOIN lv4 b) -- 4,294,967,296
,Tally_CTE (n) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM lv5)
SELECT SUBSTRING(#str, N, CHARINDEX(#Delim, #str + #Delim, N) - N) AS Item
INTO #StrTable
FROM Tally_CTE
WHERE N BETWEEN 1 AND DATALENGTH(#str) + DATALENGTH(#Delim)
AND SUBSTRING(#Delim + #str, N, LEN(#Delim)) = #Delim;
--#############################################################################
-- in both
--#############################################################################
SELECT *
FROM #Fruits F
JOIN #StrTable ST ON F.Fruit = ST.Item
--#############################################################################
-- in table but not string
--#############################################################################
SELECT *
FROM #Fruits F
LEFT JOIN #StrTable ST ON ST.Item = F.Fruit
WHERE ST.Item IS NULL
--#############################################################################
-- in string but not table
--#############################################################################
SELECT *
FROM #StrTable ST
LEFT JOIN #Fruits F ON ST.Item = F.Fruit
WHERE F.Fruit IS NULL
GO
DROP TABLE #Fruits
DROP TABLE #StrTable
You can use string_split function to do this. I tested this on SQL Server 2017 ctp 2.0 but it should work on 2016 too.
drop table if exists dbo.Fruits;
create table dbo.Fruits (
Fruits varchar(100)
);
insert into dbo.Fruits (Fruits)
values ('cherry,mango,apple'), ('peanut,cherry,mango'),
('apple,cherry,mango')
declare #str varchar(100) = 'apple,mango,cherry';
select
tt.Fruits
, COUNT(tt.value) as Value01
, COUNT(app.value) as Value02
from (
select
*
from dbo.Fruits f
outer apply string_split (f.Fruits, ',') t
) tt
left join string_split (#str, ',') app on tt.value = app.value
group by tt.Fruits

LINQ2SQL and NHibernate, grouping by calculated columns

In a SQL Server database, I have a table with log entries - timestamp and description.
I need to get logs occurrence in specified intervals (30minutes).
E.g.:
01.01.2015 00:00 - 100
01.01.2015 00:30 - 200
01.01.2015 01:00 - 2
and so on...
What I have:
var logs = session.Query<Log>;
//... other operations on logs queryable
var intervalInMinutes = 30;
var logsFrequency = logs
.GroupBy(l => new
{
Year = l.LogTimestamp.Year,
Month = l.LogTimestamp.Month,
Day = l.LogTimestamp.Day,
Hour = l.LogTimestamp.Hour,
Minute = (l.LogTimestamp.Minute / intervalInMinutes) * intervalInMinutes,
})
.Select(g => new LogsOccurence()
{
StartingDatetime = new DateTime(g.Key.Year, g.Key.Month, g.Key.Day, g.Key.Hour, g.Key.Minute, 0),
Frequency = g.Count()
})
.ToList();
Following query fails:
An exception of type 'NHibernate.Exceptions.GenericADOException' occurred in NHibernate.dll but was not handled in user code
Additional information: could not execute query
Inner exception: Column 'dbo.Log.LogTimestamp' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Generated select statement is:
select
datepart(year, Log0_.LogTimestamp) as col_0_0_
, datepart(month, Log0_.LogTimestamp) as col_1_0_
, datepart(day, Log0_.LogTimestamp) as col_2_0_
, datepart(hour, Log0_.LogTimestamp) as col_3_0_
, datepart(minute, Log0_.LogTimestamp) as col_4_0_
, cast(count(*) as INT) as col_5_0_
from
dbo.[Log] Log0_
group by
datepart(year, Log0_.LogTimestamp)
, datepart(month, Log0_.LogTimestamp)
, datepart(day, Log0_.LogTimestamp)
, datepart(hour, Log0_.LogTimestamp)
, datepart(minute, Log0_.LogTimestamp)/#p0*#p1
Name:p1 - Value:30 Name:p2 - Value:30
Operator precedence / order is wrong in groupby clause
datepart(minute, Log0_.LogTimestamp) / #p0 * #p1
Select part for minutes is different than group part for minutes - select fails
What is wrong with my Linq, and how to write correct one?
I am using NHibernate build 4.0.4.GA.
Operator precedence / order is wrong in groupby clause
The operator precedence looks correct to me. Multiplication and division have the same level of precedence, in both C# and T-SQL. Thus...
datepart(minute, Log0_.LogTimestamp) / #p0 * #p1
... is equivalent to...
(datepart(minute, Log0_.LogTimestamp) / #p0) * #p1
Select part for minutes is different than group part for minutes - select fails.
It is also different in the LINQ query. Since the GroupBy has...
Minute = (l.LogTimestamp.Minute / intervalInMinutes) * intervalInMinutes,
..., the Select should also have...
g.Key.Minute / intervalInMinutes * intervalInMinutes
That might possibly fix it.

Issue With Select Statement

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

Categories

Resources