How to GroupBy a part of DateTime using System.Dynamic.LINQ library - sql-server

I have tables that contain a lot of rows, each record is excellent by whom and on what date was added.
I want to group all records, based on AddedBy and AddedOn fields.
The problem is that the dates are in full including the miliseconds and I only want to group by day, month or year.
I hereby noted that at Compilation time I do not know which table it is and Therefore I use with System.Dynamic.LINQ library.
Below I demonstrate how did a grouping by datetime using System.Dynamic.LINQ library:
Dim groupColl= myColl.GroupBy("new(AddedName, AddedOn), it").Select("new(Key.AddedName, Key.AddedOn, Count() AS Count)")
But the problem is that I need to grouping by day, month or year.
In sql server I found how to do it, by day or by month or by year.
In Lambda Expression also found the way how to do it, but only by day.
But through System.Dynamic.LINQ not find any way how to do it.
Below I demonstrate how I'm doing this in sql server and Lambda Expression:
Using SQL SERVER:
SELECT AddedBy, DATEADD(DAY, DATEDIFF(DAY, 0, AddedOn), 0) as AddedOn, count(*)
FROM myTable
GROUP BY AddedBy, DATEADD(DAY, DATEDIFF(DAY, 0, AddedOn), 0)
Using Lambda Expression vb.net code
Dim groupColl = myCollection.GroupBy(Function(x) New With {Key x.AddedBy, Key .AddedeOn_Day = DbFunctions.TruncateTime(x.AddedOn)}).Select(Function(y) New With {y.Key.AddedBy, y.Key.AddedeOn_Day, y.Count})
I would be grateful to anyone who would help me how to do it using System.Dynamic.LINQ Library
Thanks

I found a solution!
My solution basis found here:
Using DateDiff with Linq.Dynamic library for fetching today records
Using Lambda Expression
Dim groupColl = myColl.GroupBy(Function(x) New With {Key x.AddedBy, Key .AddedeOn_Month = DbFunctions.CreateDateTime(x.AddedOn.Year, x.AddedOn.Year, x.AddedOn.Month, 1, 0, 0.0)}).Select(Function(y) New With {y.Key.AddedBy, y.Key.AddedeOn_Month , y.Count})
I added the following lines to the System.Dynamic.Linq recognize the DbFunctions:
Dim type = GetType(DynamicQueryable).Assembly.[GetType]("System.Linq.Dynamic.ExpressionParser")
Dim field = type.GetField("predefinedTypes", BindingFlags.[Static] Or BindingFlags.NonPublic)
Dim predefinedTypes = DirectCast(field.GetValue(Nothing), Type())
Array.Resize(predefinedTypes, predefinedTypes.Length + 1)
predefinedTypes(predefinedTypes.Length - 1) = GetType(DbFunctions)
field.SetValue(Nothing, predefinedTypes)
Then I added:
Dim groupColl = myColl.GroupBy("new(AddedName, DbFunctions.CreateDateTime(AddedOn.Year, AddedOn.Month, 1, 0, 0, 0.0) AS AddedOn_Month), it").Select("new(Key.AddedName, Key.AddedOn_Month, Count() AS Count)")
Now it works great.

Related

Why doesn't my datatable.compute sum code work. How do I add the filter code to the Sum function

Here's my visual basic code. I have an Access database. Income table with Income Amount, MonthYr, etc columns. I have verified data is in the table and is being loaded into the dataset. There is definitely a "January 2018" value in the MonthYr column. And I also have decimal numbers in the Income amount column.
Dim sum = IncomeTable.Compute("SUM(Income Amount)", "MonthYr = January 2018")
'code above causes this error: Missing operand after '2018' operator.
Dim sum = IncomeTable.Compute("SUM(Income Amount)", "MonthYr = 'January 2018'")
'code above causes this error: Syntax error in aggregate argument: Expecting a single column argument with possible 'Child' qualifier.
Dim sum = IncomeTable.Compute("SUM(Income Amount)", "MonthYr = [January 2018]")
' code above causes this error: Cannot find column [January 2018].
-In Access, The Income Amount column is currency datatype, and MonthYr column is short text datatype
-I have tried various other things like using an _underscore to replace the spaces in column name and in "January 2018"
-I have been looking all over msdn and google and tried every variation of the code I could come up with.
Your syntax is totally off - wonder where you got that from.
It could be:
Dim SumAmount As Currency
SumAmount = DSum("[Income Amount]", "IncomeTable", "MonthYr = 'January 2018'")
In VB:
Open a recordset:
"Select Sum([Income Amount]) From IncomeTable Where MonthYr = 'January 2018'"

SQL Server - How to Use Merge Statement for Slowly Changing Dimension with More Than Two Conditions?

I am trying to implement Slowly Changing Dimension Type 2 through T-SQL but I can't figure out how to put a request to work.
Table columns: cpf, nome, telefone_update, endereco_insert
Basically the logic is: if the MATCH doesn't happen using cpf, then the record must be inserted; if the MATCH happens but only the telefone_update field has changed, there is no need to another record and I just want to UPDATE and override the values; if the MATCH happens but only the endereco_insert field has changed I want to add a new record and update the start and end dates.
What I have so far is:
insert into #dm_lucas_tst (
[cpf],
[nome],
[telefone_update],
[endereco_insert],
[dt_scd_start],
[dt_scd_end],
[nu_scd_version]
)
select [cpf],
[nome],
[telefone_update],
[endereco_insert],
cast(dateadd(month, datediff(month, 0, getdate()), 0) as date) as [dt_scd_start],
'2199-12-31' AS [dt_scd_end],
1 AS [nu_scd_version]
from (
merge edw.dim.dm_lucas_tst as Target
using edw.dim.stg_lucas_tst as Source
on Target.cpf = Source.cpf
when not matched by target
then
insert (
[cpf],
[nome],
[telefone_update],
[endereco_insert],
[dt_scd_start],
[dt_scd_end],
[nu_scd_version]
)
values (
Source.[cpf],
Source.[nome],
Source.[telefone_update],
Source.[endereco_insert],
cast(dateadd(month, datediff(month, 0, getdate()), 0) as date),
'2199-12-31',
1
)
when matched
and Source.telefone_update <> Target.telefone_update
and Target.dt_scd_end = '2199-12-31'
then
update set telefone_update = Source.telefone_update
output $ACTION ActionOut,
Source.[cpf],
Source.[nome],
Source.[telefone_update],
Source.[endereco_insert]
) AS MergeOut
where MergeOut.ActionOut = 'UPDATE';
But I don't think putting another WHEN MATCH AND ... will make that work.
Any suggestions?
Thanks in advance!
Accordingly to your description, I'm assuming that you need:
SCD Type 1 for column [telefone_update]
SCD Type 2 for column [endereco_insert]
I've used application SCD Merge Wizard to easily create described logic.
When I made tests for it - everything looks as expected, I guess.
I described the process on my blog - please have a look and tell me if that was exactly what you wanted?
https://sqlplayer.net/2018/01/scd-type-1-type-2-in-merge-statement/

SQL Server, Having Clause, Where, Aggregate Functions

In my problem which I am trying to solve, there is a performance values table:
Staff PerformanceID Date Percentage
--------------------------------------------------
StaffName1 1 2/15/2016 95
StaffName1 2 2/15/2016 95
StaffName1 1 2/22/2016 100
...
StaffName2 1 2/15/2016 100
StaffName2 2 2/15/2016 100
StaffName2 1 2/22/2016 100
And the SQL statement as follows:
SELECT TOP (10)
tbl_Staff.StaffName,
ROUND(AVG(tbl_StaffPerformancesValues.Percentage), 0) AS AverageRating
FROM
tbl_Staff
INNER JOIN
tbl_AcademicTermsStaff ON tbl_Staff.StaffID = tbl_AcademicTermsStaff.StaffID
INNER JOIN
tbl_StaffPerformancesValues ON tbl_AcademicTermsStaff.StaffID = tbl_StaffPerformancesValues.StaffID
WHERE
(tbl_StaffPerformancesValues.Date >= #DateFrom)
AND (tbl_AcademicTermsStaff.SchoolCode = #SchoolCode)
AND (tbl_AcademicTermsStaff.AcademicTermID = #AcademicTermID)
GROUP BY
tbl_Staff.StaffName
ORDER BY
AverageRating DESC, tbl_Staff.StaffName
What I am trying to do is, from a given date, for instance 02-22-2016,
I want to calculate average performance for each staff member.
The code above gives me average without considering the date filter.
Thank you.
Apart from your join conditions and table names which looks quite complex, One simple question, If you want the results for a particular date then why is the need of having
WHERE tbl_StaffPerformancesValues.Date >= #DateFrom
As you said your query is displaying average results but not for a date instance. Change the above line to WHERE tbl_StaffPerformancesValues.Date = #DateFrom.
Correct me if I am wrong.
Thanks for the replies, the code above, as you all say and as it is also expected is correct.
I intended to have a date filter to see the results from the given date until now.
The code
WHERE tbl_StaffPerformancesValues.Date >= #DateFrom
is correct.
The mistake i found from my coding is, in another block i had the following:
Protected Sub TextBoxDateFrom_Text(sender As Object, e As System.EventArgs) Handles TextBoxDate.PreRender, TextBoxDate.TextChanged
Try
Dim strDate As String = Date.Parse(DatesOfWeekISO8601(2016, WeekOfYearISO8601(Date.Today))).AddDays(-7).ToString("dd/MM/yyyy")
If Not IsPostBack Then
TextBoxDate.Text = strDate
End If
SqlDataSourcePerformances.SelectParameters("DateFrom").DefaultValue = Date.Parse(TextBoxDate.Text, CultureInfo.CreateSpecificCulture("id-ID")).AddDays(-7)
GridViewPerformances.DataBind()
Catch ex As Exception
End Try
End Sub
I, unintentionally, applied .AddDays(-7) twice.
I just noticed it and removed the second .AddDays(-7) from my code.
SqlDataSourcePerformances.SelectParameters("DateFrom").DefaultValue = Date.Parse(TextBoxDate.Text, CultureInfo.CreateSpecificCulture("id-ID"))
Because of that mistake, the SQL code was getting the performance values 14 days before until now. So the average was wrong.
Thanks again.

Update query failed '0' rows affected

I am trying to run this query but the query keeps giving up on me:
Update StockInvoiceInfo set Quantity = Quantity - 2 where p_id = 5 AND ProductDate = convert(Cast('31-5-2015' as datetime)) ;
After Running this code it returns an error below:
Incorrect syntax near '31-5-2015'
The datatype of the ProductDate column isDate. I am using Sql Server 2012.
You have used Convert functions but didn't supplied it with parameters. Also there is no need for this function here. Also take care of date format. I have changed it to standard format:
Update StockInvoiceInfo set Quantity = Quantity - 2
where p_id = 5 AND ProductDate = Cast('2015-05-31' as datetime)
If all you are trying to do is compare a Sql Date, then just use an agnostic format like '20150531' or easier to read '2015-05-31'. No need for casts or convert at all, i.e.
WHERE ... AND ProductDate = '2015-05-31'
However, if ProductDate isn't a date, but one of the *DATETIME* data types, and you are looking to update any time on the same day, then I believe you are looking for something like:
Update StockInvoiceInfo
set Quantity = Quantity - 2
where
p_id = 5
AND CAST(ProductDate AS DATE) = '2015-05-31';
However, the performance will be lousy as the clause isn't likely to be SARGable. You're better off simply doing:
AND ProductDate >= '2015-05-31' AND ProductDate < '2015-06-01';
(Resist the temptation to use between, or hacks like ':23:59:59' as there will be data corner cases which will bite you)
use CAST('5-31-2015' as DATETIME)
with the above update statement you started convert but with incomplete syntax
here the convert syntax
Update StockInvoiceInfo
set Quantity = Quantity - 2
where p_id = 5
AND ProductDate = convert(datetime,Cast('31-5-2015' as varchar),103) ;

How to get the Start Date of the current Quarter populated in SSRS?

I am generating a report in SSRS, in which I got a start date field, which should populate the Start date of the current quarter automatically. Can someone please help me, how do I do this?. Thanks heaps
T-SQL for current quarter:
SELECT DATEADD(qq,DATEDIFF(qq,0,GETDATE()),0) AS FirstDayOfCurrentQtr
Or SSRS expression if you want to set the value that way:
=DateAdd(DateInterval.Quarter, DateDiff(DateInterval.Quarter, CDate("1/1/1900"), Today()), CDate("1/1/1900"))
if you wanted to avoid having an additional dataset, you could use this expression as the default value for the parameter:
=DateSerial(Datetime.Today.Year,3 * ((datetime.Today.Month -1 )/3 + 1) -2, 1)
That's pretty ugly though. More ideally create a function that you cacan call that from the expression:
Function getQuarter (byVal d As DateTime) As DateTime
Dim quarter as Integer = (d.Month -1) / 3 + 1
Dim quarterStart AS new DateTime(d.Year, 3 * quarter - 2, 1)
getQuarter = quarterStart
End Function
Put the above in the code section of the report properties and in the expression call it by:
=Code.GetQuarter(Today)

Resources