Cursor to return multiple rows - c#

I've been working on this for the past few days and I can't find my way out of it. I have a C# web application that needs to print reports on screen. This same application calls a stored procedure on the database (Oracle) and it returns a cursor. Here is the procedure
PROCEDURE report_total(beginDate IN DATE, endDate IN DATE, c OUT REF CURSOR)
AS
BEGIN
OPEN
c
FOR
SELECT
month
,sum(field1)
-- + a lot of other fields
FROM
view1 v
WHERE
beginDate <= v.date
AND v.Date < endDate
GROUP BY
month
END;
This works fine, it gives me the sum of field1 (and others) per months. Assuming you enter, at least, a complete year range you'll get, at most, 12 rows. Howhever. I would like to make something a similar stored procedure that would give me the detail of these months.
Let's say beginDate = '2003-01-01' and the endDate = '2005-01-05' (YYYY-MM-DD), I would need 25 rows. One per month, per year. And I would like to get these results with the cursor OUT. If you have a simplest idea that wouldn't involve a cursor please suggest me.

SELECT TRUNC(v.date, 'MONTH'), SUM(field1)
FROM view1 v
WHERE v.date BETWEEN beginDate and endDate
GROUP BY
TRUNC(v.date, 'MONTH')

Related

SQL stored procedure to pass date value in months/years

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.

Calculating how old a datetime value is taking working hours into account

I'm creating an ASP.NET application (C#), I'm nearly finished however I have the following question.
Scenario
In my MSSQL table I have a datetime value i.e. 2015-05-06 13:38:17.000 I need to find out if this is over 6 hours old but I need to take into account the fact we are only working from 8:30-18:00 Monday to Friday.
I currently work out if an item is over 4 hours old (not taking working hours into account) using the following query:
SELECT COUNT(*) FROM Table WHERE [DateSubmitted] < DATEADD(HOUR,-4,GETDATE())
I've read up on how to calculate the working hours: Calculate business hours between two dates but I don't know how to apply this to what I want to do.
Any help would be appreciated - thank you.
Just get the max date within business hour and do your query with that parameter
DECLARE #EndDate DATETIME, #StartBusinessDay DATETIME, #YesterdayEndBusinessDay DATETIME,#Interval DECIMAL(10,2)
SET #Interval=4*3600*-1
--set start period of business hour
--you can change hard coded date to variable one
SELECT #StartBusinessDay=CAST('2015-06-17 08:00:00' AS datetime),
#YesterdayEndBusinessDay =CAST('2015-06-16 17:00:00' AS datetime)
--get maximal date with basic calculation
SELECT #EndDate=DATEADD(ss,#Interval, GETDATE())
--if max date is not within business hour, do this
IF(#EndDate<#StartBusinessDay)
BEGIN
DECLARE #Difference DECIMAL(4,2)
--get the difference between result of basic calculation and start business hour
SELECT #Difference=DATEDIFF(ss, #EndDate, #StartBusinessDay)
--subtract it with initial interval
SET #Difference=#Interval-#Difference;
--get the new max date within business hour
SELECT #EndDate=DATEADD(ss,#Difference,#YesterdayEndBusinessDay)
SELECT #EndDate
END
--query with max date within business hour
SELECT COUNT(1) FROM Table
WHERE [DateSubmitted] < #EndDate

SQL Query with Long Date Time?

I am trying to pass a SQL query through c# , currently it is based on just the day month and year with time always set to 0 EG 1997-10-28 00.00.00.000 which is great as the time never changes it easy for me to just Select Where date equals the calendar date.
However with the Start Field , the time is different on each record , eg 1899-12-30 14.14:00.00.000 , 1899-12-30 15.14:30.00.000 . (Seconds downwards are always the same) .
So I need to have a query that will return all the results of the selected date on the "Start" field . How would I do this?.
E.G IF i click the calendar which passes 1997-10-28 00.00.00.000 , I would like the results of every time in that day!. How do I go about that?.
Thanks for any input.
EDIT: Is there a way to format the date that i have in SQL ?. This comes from an old access database!. and as you can see above it is 1899-12-30 ?. not 1998 , I don't know why this has happened!.
WHERE DATEDIFF(dd, your_start_field, #your_param) = 0
You need to select all record between today and tomorrow without including tomorrow's date.
WHERE EventDate >= StartDate AND EventDate < DATEADD(d, 1, StartDate)
Can you not just query the date part. I think this should work...
SELECT * FROM Table1 WHERE StartDate = '1997-10-28'
EDIT: Above may not work but following should cover needs
SELECT * FROM Table1 WHERE StartDate >= '1997-10-28 00:00:00.000' AND StartDate < '1997-10-29 00:00:00.000'
(notice the second date is the following date)
This SQL DATEADD(d,datediff(d,0,startdate),startdate) will convert a date with time to just the date;
eg
Select field1,field2 from mytable where DATEADD(d,datediff(d,0,startdate),startdate)='1997-10-28'

SQL statement to get data from a week back?

I am new to SQL statements and I am having a little trouble getting data from a week ago based on the date modified.
SELECT People.first, People.last, company.companyname, People.lastmodified
FROM job_prof
INNER JOIN People ON job_prof.cid = People.cid
INNER JOIN company ON job_prof.Id = company.id
-> WHERE People.lastmodified = DATE(DATE_ADD(GETDATE(), INTERVAL -7 DAY))
ORDER BY People.lastmodified DESC";
Example of Date in the table is 6/9/2011 12:08:01 PM
Any suggestions will be helpful.
Thank you
WHERE DATEDIFF(day, People.lastmodified, GETDATE()) <= 7
The trick with dates is to create a range first with DATEADD and whatever else you need, I.e.
declare #start datetime = ...,
#end datetime = ...
Then search in that range; I typically include the start and exclude the end, as this allows a simple "data between the 10th and 12th"
where row.lastmodified >= #start
and row.lastmodified < #end
Having a range is critical unless the values are entire units (days, etc) - otherwise equality won't work very well. And the simple >= and < use allows effective use of indexing etc.
If it's a range you're looking for, such as anything modified starting a week ago and ending a week before that, BETWEEN makes this pretty easy.
WHERE People.lastmodified BETWEEN DATEADD(week, -1, getdate()) AND DATEADD(week, -2, getdate())

How to determine closest date

I am a little confused about how or what the best way to determine what the closest date is to DateTime.Now is.
In my table, everything needs to be timestamped. And on a page, I need to be able to retrieve everything from the table only if the date is the closest date to now.
How would I go about this?
I am using DateTime.Now when inserting dates into the Database, and the format is like:
5/07/2011 5:28:57 PM
Here's my suggestion:
declare #DateTimeNow datetime = getdate()
select TOP (1)
RecordId
,MyDateColumn
,abs(datediff(s, MyDateColumn, #DateTimeNow)) as Diff
from
MyTable
order by
abs(datediff(s, MyDateColumn, #DateTimeNow)) asc
Do not forget to use ABS()!
How about
SELECT TOP 1 *
FROM MyTable
ORDER BY TimestampColumn DESC
Consider storing time in UTC - DateTime.UtcNow
In T-SQL you could use DateDiff:
DATEDIFF ( datepart , startdate , enddate )
http://msdn.microsoft.com/en-us/library/ms189794.aspx
or in C# you could use TimeSpan:
http://msdn.microsoft.com/en-us/library/system.timespan.aspx#Y3719
Do you only have past dates, meaning, will you ever have a date that is newer than DateTime.Now? If not, you could get by with a simple Order By on the date column selecting the newest date. Otherwise, you'll need to get a date difference between your DateTime.Now, and order by that result. e.g.
SELECT TOP 1
columnDate
FROM table1
ORDER BY DATEDIFF (ss,#passedInDate,columnDate)
This would essentially look for all future and past dates using your #passedInDate (DateTime.Now) as the qualifier or base date. I'm using seconds as the time interval to compare in my example, but you can change that to whatever makes the most sense for you.
Also, you shouldn't need to pass in DateTime.Now to SQL server, as you can use the built in GetDate() function.
Something like this should work:
SELECT TOP 1 * FROM MyTable ORDER BY ABS(DATEDIFF(DD, getdate(), DATE))
This should sort your rows by the closest date, past or future. If you need it more precise then just days, change DD to something else, as specified here

Categories

Resources