I am working on a C#/WPF application and connecting it with SQL.
I am trying to write a stored procedure in SQL that takes a selected date and converts it into (month, year) so at the time of executing, for example I put 1 for January and 2018 for the year and it will display the total sales for 2018 (that occurred in any given month in this case, January)
Ultimately in C#, the user will choose any given month from a comboBox, same for the year and click show sales and it should display using the stored procedure.
So far, I have this in SQL
ALTER PROCEDURE [dbo].[salesForSelectedMonth]
-- Add the parameters for the stored procedure here
#date date
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT SUM (TotalPrice) AS TOTAL_SALES, YEAR([TruckRental-PB].RentDate) AS year, MONTH([TruckRental-PB].RentDate) AS month
FROM [TruckRental-PB]
WHERE MONTH(#date) = MONTH([TruckRental-PB].RentDate)
AND YEAR(#date) = YEAR([TruckRental-PB].RentDate)
GROUP BY [TruckRental-PB].RentDate;
END
The issue is this is only allowing for putting a date then it shows the total sale
what I want is to get from C# the month (data type int), year (int) pass it to SQL proc to produce total sales
This is the logic I have so far (getting a datepicker value and passing it to the above proc) but getting an error still
public static int monthlySales (DateTime date)
{
using (Data_Context ctx = new Data_Context())
{
int sales = int.Parse(ctx.TruckRentalPbs.FromSqlRaw("salesForSelectedMonth", date).FirstOrDefault().ToString());
return sales;
}
System.InvalidOperationException: ''FromSqlRaw' or
'FromSqlInterpolated' was called with non-composable SQL and with a
query composing over it. Consider calling 'AsEnumerable' after the
method to perform the composition on the client side.'
UPDATE
I was able to pass month and year as int inside stored procedure however now it is showing the year as 1905 - any idea why?
-- Fetch matching month and year only
WHERE
#month = MONTH([TruckRental-PB].RentDate)
AND
#year = YEAR([TruckRental-PB].RentDate)
GROUP BY YEAR([TruckRental-PB].RentDate), MONTH([TruckRental-PB].RentDate)
Outcome
Your problem isn't really related to the type of parameter you pass, at least not your first problem. Your code
int sales = int.Parse(ctx.TruckRentalPbs.FromSqlRaw("salesForSelectedMonth", date).FirstOrDefault().ToString());
can't work this way. Entity Framework needs to map the result from FromSqlRaw to the entities it knows. But here you are returning an unknown result set where it doesn't know anything about its structure.
The workaround for this is to turn the result from EF into a memory bound collection and then use regular LINQ queries for the remaining code:
int sales = int.Parse(ctx.TruckRentalPbs.FromSqlRaw("salesForSelectedMonth", date).AsEnumerable().FirstOrDefault().ToString());
Then you can change the parameters by replacing the date parameter with two INT parameters and pass both into the query.
Related
I want to execute the script as below with Linq.
//Oracle script
UPDATE Table1 SET UPDATETIME = SYSDATE WHERE USERID = '1';
//Linq
var updateTbl = DbContext.Table1.Where(x=>x.USERID == "1").FirstOrDefalt();
updateTbl.UPDATETIME = DateTime.Now;
DbContext.SaveChange();
But after I retrieve the sql script, I found that Linq didn't use sysdate.
update "Table1"
set "UPDATETIME" = :p0
where ("USERID" = :p1)
-- :p0: '2021/3/4 09:55:07' (Type = DateTime) //DateTime on client instead of Oracle sysdate.
-- :p1: '1' (Type = String, Size = 128)
Some client will have wrong datetime, so I want to save datetime with oracle datetime instead of client datetime.
How to do it with Linq?
I want to execute the script like below.
update "Table1"
set "UPDATETIME" = :p0
where ("USERID" = :p1)
-- :p0: sysdate (Type = DateTime)
-- :p1: '1' (Type = String, Size = 128)
Entity framework doesn't update rows in sets. First, you retrieve the objects (your FirstOrDeault materialize the object), then you modify the objects in memory, and last EF generate update sentences for each modified object (in SaveChanges method).
Since the updateTbl.UPDATETIME = DateTime.Now is executed in memory, it does not execute SQL code. The update code is generated way after the value has changed.
If you need to execute SQL without retrieving the object, you could use DbContext.Database.ExecuteSqlCommand. This let you create arbitrary or parametrized SQL, but, if you are modifying other fields, it may be hard to maintain.
I assume running app server and database server are not synchronized, and want to use the DB server time. Could you force the servers to synchronize?
Other option could be using a trigger in the table that updates the column each time the row is inserted / updated.
I am working on a website in asp.net. I am getting a date from a web page and then depending on the user input I want to get results from SQL Server database (using stored procedures).
Problem is that I am getting date only from UI in this format 2016-10-08 which is of type string. But in the database, I have a column which is of type datetime in this format 2016-10-08 17:38:00.000.
I am using this query to search but it does not work.
select *
from table
where acceptedDate like #sDate+ '%';
where sDate is input parameter for stored procedure. Please help. thanks
Don't pass dates as strings. Pass them as DateTime.
The .Net DateTime maps directly to SQL Server's DateTime. All you have to do is parse the string to a DateTime struct in your .Net code and pass it as a parameter to your stored procedure.
To search for a specific date and ignore the Time portion of the DateTime, better use >= and < in your sql:
select *
from table
where acceptedDate >= #Date
AND acceptedDate < DATEADD(DAY, 1, #Date);
If you only want compare with day level and ignoring the hours part, you can use DateDiff function.
Pass d or DAY to interval parameter of DateDiff
For example:
DECLARE #sDate VARCHAR(100)='2016-10-08'
IF ISDATE(#sDate)=1
BEGIN
select *
from table
where datediff(d,acceptedDate,#sDate)=0 --same day
END
ELSE
PRINT 'Invalid date format!'
I am using SQL server and stored procedures and I want to do a simple SELECT.
In my table I have a DATE format, which shows correctly in the database as yy-mm-dd.
When I call the stored procedure in my C# app, I also get a time value for every row (11/14/1987 12:00:00 AM).
How can I remove the time format?
Here is my select stored procedure:
ALTER procedure [dbo].[Employee_GetAllEmployees]
AS
BEGIN
SELECT * FROM
dbo.Employee
END
If you want only date then use convert() :
SELECT emp.*, CONVERT(DATE, date_col) AS New_date
FROM dbo.Employee emp;
The SQL Server date data type maps to .NET DateTime, which includes a time component. For formatting purposes in your application, use ToString according to your desired display format.
var formattedDateString = dateTypeField.ToString("yyyy-MM-dd");
Although you can format the value in T-SQL and return a string instead, burdening the database server for presentation formatting limits performance and scalability and is not considered a best practice.
I've been currently working on a stored procedure that grabs all the clients I have in the database that have loans. How I'm filtering the results is by the start and end dates given when generating the data. The way my data works is that the returned table will have multiple date fields, 9 date fields to be precise. Each of these date fields are used depending on the LoanStatus field that is also a part of this table. LoanStatus can have values such as Settled, Approved, Cancelled.. What I want to do is to filter the results using this start and end date but applying it to all of the date fields
In my head I've got a couple of pseudo ways to possibly work this issue out:
First Possible Solution
Need some code that'll allows me to essentially do this:
allDatefields > #startDate AND allDatefields < #endDate.
Second Possible Solution
Is to only take into consideration the date field that matches with the loan status. For example, if the LoanStatus is Settled, then look at the DateSettled column of the table, or if the LoanStatus is Approved, then look at the ApprovalDate column of the database.
Personally, I would love to be able to filter through and apply the #startDate and #endDate to all date fields rather than have to look at each date seperately.
Is there a way in SQL Server to apply a WHERE clause to all date fields in a table?
To my knowledge, the where clause does not support your first scenario. I think you might have to settle for something like this:
(LoanStatus = 'Approved' and ApprovalDate > #startDate AND ApprovalDate < #endDate) OR (LoanStatus = 'Settled' and SettleDate > #startDate AND SettleDate < #endDate) OR ... same for the rest of loan status values
SQL Function For Generating Year Wise Client Code:
The following sql function will generate year wise client code based on server-date. such as for 2012 client the codes will be
CL12-00001, CL12-00002,....and for 2013 the codes will be
CL13-00001, CL13-00002,....etc.
(Here CL means client, 12 for year 2012, 13 for year 2013.)
CREATE function [dbo].[GenClientCode]()
returns nvarchar(20)
as
begin
Declare #Code nvarchar(20), #cyear nvarchar(2);
SET #cyear= ( SUBSTRING(CONVERT(nvarchar(2),DATEPART(year, sysdatetime())),3,2));
SET #Code= (Select MAX(CONVERT(INT, SUBSTRING(ClientCode,6, LEN(ClientCode))))+1
from tblClientInfo WHERE SUBSTRING(ClientCode,3,2)=#cyear);
--assume the code format is like CL12-00001, here 12 for year 2012
if (#Code is null or #Code='')
set #Code='00001'
else if LEN(#Code)=1
set #Code='0000'+ CONVERT(nvarchar(1),#Code);
else if LEN(#Code)=2
set #Code='000'+ CONVERT(nvarchar(2),#Code);
else if LEN(#Code)=3
set #Code='00'+ CONVERT(nvarchar(3),#Code);
else if LEN(#Code)=4
set #Code='0'+ CONVERT(nvarchar(4),#Code);
set #Code='CL'+#cyear+'-'+ CONVERT(nvarchar(10),#Code);
return #Code;
end
Is my function is optimum or not?
Your idea has several obvious problems such as "what happens in the year 2100?" and "what happens if there more than 99999 codes in a year?". Also there are a few less obvious issues such as "what happens if two codes are requested at nearly the same time?" and the fact that you're doing a query off a substring which means that SQL Server can't use an index (meaning your performance may be bad).
"How do I get a 2-digit year?" and "how do I left-pad strings?" seems to have been answered by Kaf.
If you're on SQL Server 2012, I would suggest looking into sequences. If you're on an earlier version, I would suggest putting a new table into your database with two integer fields representing the year and the next available number for that year and then changing your scalar function to a stored procedure that is able to query and update that table using an exclusive lock. This would allow you to find the next number quickly using an indexed small table rather than doing a table scan over what I assume to be a large table. Also this would help protect you from possible duplicates if your system is under pressure.
Getting MAX+1 for the next record is not very accurate. Better solution would be to have an auto incremented identity(1,1) column, say IdCol and a date column, say dateCol. Then you can form your specific code on SELECT as;
SELECT 'CL' + RIGHT(DATEPART(yy,dateCol),2) + '-' +
RIGHT('00000' + CONVERT(VARCHAR(5),idCol),5)
--Note:Max clients 99999
However, your function also can be optimised as;
CREATE function [dbo].[GenClientCode]()
returns varchar(20)
AS
BEGIN
Declare #code varchar(20), #cyear varchar(2);
SELECT #cyear = RIGHT(DATEPART(yy,Getdate()),2);
SELECT #code = ISNULL( MAX(
SUBSTRING(ClientCode, CHARINDEX('-', ClientCode) + 1,
LEN(ClientCode))
), 0)+1
FROM tblClientInfo
WHERE SUBSTRING(ClientCode,3,2) = #cyear
RETURN 'CL' + #cyear + '-' + RIGHT('00000' + #code, 5)
END