Max Date between 2 dates - sql-server

How can I find the latest date in a column but constrain it between 2 dates
SELECT [Weight]
FROM [weighinevent] w
WHERE [Date] = (SELECT MAX([Date]) WHERE [Date] BETWEEN #StartDate AND #EndDate AND w.[userid] = #userid )
This is what I have. Is that correct?

No, it is not correct. Subqueries need to define the table too from which they are selecting. But you can order by the date and take only the first record
SELECT top 1 Weight
FROM weighinevent
WHERE Date BETWEEN #StartDate AND #EndDate
AND userid = #userid
ORDER BY Date DESC

Related

SQL Query returning multiple values

I am trying to write a query that returns the time taken by an Order from start to completion.
My table looks like below.
Order No. Action DateTime
111 Start 3/23/2018 8:18
111 Complete 3/23/2018 9:18
112 Start 3/24/2018 6:00
112 Complete 3/24/2018 11:10
Now I am trying to calculate the date difference between start and completion of multiple orders and below is my query:
Declare #StartDate VARCHAR(100), #EndDate VARCHAR(100), #Operation VARCHAR(100)
declare #ORDERTable table
(
order varchar(1000)
)
insert into #ORDERTable values ('111')
insert into #ORDERTable values ('112')
Select #Operation='Boiling'
set #EndDate = (SELECT DATE_TIME from PROCESS WHERE ACTION='COMPLETE' AND ORDER in (select order from #ORDERTable) AND OPERATION=#Operation)
---SELECT #EndDate
set #StartDate = (SELECT DATE_TIME from PROCESS WHERE ACTION='START' AND ORDER in (select order from #ORDERTable) AND OPERATION=#Operation)
---SELECT #StartDate
SELECT DATEDIFF(minute, #StartDate, #EndDate) AS Transaction_Time
So, I am able to input multiple orders but I want to get multiple output as well.
And my second question is if I am able to achieve multiple records as output, how am I gonna make sure which datediff is for which Order?
Awaiting for your answers. Thanks in advance.
I am using MSSQL.
You can aggregate by order number and use MAX or MIN with CASE WHEN to get start or end time:
select
order_no,
max(case when action = 'Start' then date_time end) as start_time,
max(case when action = 'Completed' then date_time end) as end_time,
datediff(
minute,
max(case when action = 'Start' then date_time end),
max(case when action = 'Completed' then date_time end)
) as transaction_time
from process
group by order_no
order by order_no;
You can split up your table into two temp tables, cte's, whatever, and then join them together to find the minutes it took to complete
DECLARE #table1 TABLE (OrderNO INT, Action VARCHAR(100), datetime datetime)
INSERT INTO #table1 (OrderNO, Action, datetime)
VALUES
(111 ,'Start' ,'3/23/2018 8:18'),
(111 ,'Complete' ,'3/23/2018 9:18'),
(112 ,'Start' ,'3/24/2018 6:00'),
(112 ,'Complete' ,'3/24/2018 11:10')
;with cte_start AS (
SELECT orderno, Action, datetime
FROM #table1
WHERE Action = 'Start')
, cte_complete AS (
SELECT orderno, Action, datetime
FROM #table1
WHERE Action = 'Complete')
SELECT
start.OrderNO, DATEDIFF(minute, start.datetime, complete.datetime) AS duration
FROM cte_start start
INNER JOIN cte_complete complete
ON start.OrderNO = complete.OrderNO
Why don't you attempt to approach this problem with a set-based solution? After all, that's what a RDBMS is for. With an assumption that you'd have orders that are of interest to you in a table variable like you described, #ORDERTable(Order), it would go something along the lines of:
SELECT DISTINCT
[Order No.]
, DATEDIFF(
minute,
FIRST_VALUE([DateTime]) OVER (PARTITION BY [Order No.] ORDER BY [DateTime] ASC),
FIRST_VALUE([DateTime]) OVER (PARTITION BY [Order No.] ORDER BY [DateTime] DESC)
) AS Transaction_Time
FROM tableName
WHERE [Order No.] IN (SELECT Order FROM #ORDERTable);
This query works if all the values in the Action attribute are either Start or Complete, but also if there are others in between them.
To read up more on the FIRST_VALUE() window function, check out the documentation.
NOTE: works in SQL Server 2012 or newer versions.

Select count with 0 count

Lets say I have following query:
SELECT top (5) CAST(Created AS DATE) as DateField,
Count(id) as Counted
FROM Table
GROUP BY CAST(Created AS DATE)
order by DateField desc
Lets say it will return following data set
DateField Counted
2016-01-18 34
2016-01-17 99
2016-01-14 1
2015-12-28 1
2015-12-27 6
But when I have Counted = 0 for certain Date I would like to get that in result set. So for example it should look like following
DateField Counted
2016-01-18 34
2016-01-17 99
2016-01-16 0
2016-01-15 0
2016-01-14 1
Thank you!
Expanding upon KM's answer, you need a date table which is like a numbers table.
There are many examples on the web but here's a simple one.
CREATE TABLE DateList (
DateValue DATE,
CONSTRAINT PK_DateList PRIMARY KEY CLUSTERED (DateValue)
)
GO
-- Insert dates from 01/01/2015 and 12/31/2015
DECLARE #StartDate DATE = '01/01/2015'
DECLARE #EndDatePlus1 DATE = '01/01/2016'
DECLARE #CurrentDate DATE = #StartDate
WHILE #EndDatePlus1 > #CurrentDate
BEGIN
INSERT INTO DateList VALUES (#CurrentDate)
SET #CurrentDate = DATEADD(dd,1,#CurrentDate)
END
Now you have a table
then you can rewrite your query as follows:
SELECT top (5) DateValue, isnull(Count(id),0) as Counted
FROM DateList
LEFT OUTER JOIN Table
on DateValue = CAST(Created AS DATE)
GROUP BY DateValue
order by DateValue desc
Two notes:
You'll need a where clause to specify your range.
A join on a cast isn't ideal. The type in your date table should match the type in your regular table.
One more solution as a single query:
;WITH dates AS
(
SELECT CAST(DATEADD(DAY, ROW_NUMBER() OVER (ORDER BY [object_id]) - 1, '2016-01-14') as date) 'date'
FROM sys.all_objects
)
SELECT TOP 5
[date] AS 'DateField',
SUM(CASE WHEN Created IS NULL THEN 0 ELSE 1 END) AS 'Counted'
FROM dates
LEFT JOIN Table ON [date]=CAST(Created as date)
GROUP BY [date]
ORDER BY [date]
For a more edgy solution, you could use a recursive common table expression to create the date list. PLEASE NOTE: do not use recursive common table expressions in your day job! They are dangerous because it is easy to create one that never terminates.
DECLARE #StartDate date = '1/1/2016';
DECLARE #EndDate date = '1/15/2016';
WITH DateList(DateValue)
AS
(
SELECT DATEADD(DAY, 1, #StartDate)
UNION ALL
SELECT DATEADD(DAY, 1, DateValue)
FROM DateList
WHERE DateList.DateValue < #EndDate
)
SELECT DateValue, isnull(Count(id),0) as Counted
FROM DateList
LEFT OUTER JOIN [Table]
ON DateValue = CAST(Created AS DATE)
GROUP BY DateValue
ORDER BY DateValue DESC

SQL SUM filter query

We have a table with the following information:
table1
I need T-SQL code that receives a "start date" and "end date and would generate the invoice total, grouped by customer id and invoice type, of all invoices generated within the date range AND the total invoiced for that customer (credit and cash combined).
For instance, the result if we provide start date 01-10-2012 and end date 10-11-2012 should be:
result_table
This is what I have:
DECLARE #startdate DATE, #enddate DATE
SET #startdate = '01-10-2012'
SET #enddate = '10-11-2012'
SELECT CustomerId, InvoiceType, SUM(Total) As Total
FROM Invoices
WHERE Date BETWEEN #startdate AND #enddate
GROUP BY CustomerID, InvoiceType
It works fine, but I am unable to come up with a way to calculate the "total2" column, since I'm already grouping rows by "invoicetype".
Help, please.
Thank you.
This should work:
SELECT CustomerId, InvoiceType, SUM(Total) As Total
, (
SELECT SUM(Total) FROM Invoices t2 WHERE t2.CustomerId=t1.CustomerId
) AS Total2
FROM Invoices t1
WHERE Date BETWEEN #startdate AND #enddate
GROUP BY CustomerID, InvoiceType

SQL Server group by / count issue

I'm trying to count Holiday bookings (B.ID) for dates 2 days either side of today.
It works but my results are separated as I have to introduce the end date of
the holiday too, which varies for each start date (holidays have different durations).
The separates out my counts. What I need is one count for each date. Is there a way of working round this? I kinda just want to exclude the vwReturnDate from the group by but have to put it there as I've used it in my count.
In English I want - For each [date] count the number of [B.id] where [B.Depart] <= [date] and [vwReturnDate] > [date]
DECLARE #startDate DATE
DECLARE #endDate DATE
SET #startDate = Getdate()-2
SET #endDate = Getdate()+2;
WITH dates(Date) AS
( SELECT #startdate as Date
UNION ALL
SELECT DATEADD(d,1,[Date])
FROM dates
WHERE DATE < #enddate )
SELECT
[Date] as 'Calendar Date',
--CONVERT(VARCHAR(10), [Date],103) AS 'Date'
-- ,CONVERT(CHAR(2), [Date], 113) AS 'Day'
-- ,CONVERT(CHAR(4), [Date], 100) AS 'Month'
-- ,CONVERT(CHAR(4), [Date], 120) AS 'Year',
Case when B.Depart <= [date] AND vwR.ReturnDate >=[date] then count (B.ID) end AS 'Number of holidays live on date'
FROM [dates]
left join Booking B on B.depart=[Date]
inner join Quote Q on Q.ID=B.QuoteID
inner join vwReturnDate vwR on vwR.ID=B.ID
Group by [date], B.depart, vwR.ReturnDate
order by [date]
OPTION (MAXRECURSION 0)
GO

SQL Server query to calculate total for number of weeks in a given month name

I need to create a report where I will just pass month (February) and year (2011) and want the sum(total) but output desired like this... I don't know how to calculate total weekwise
Week-1......Week-2......Week-3......Week-4....Total
---------------------------------------------------
Working example
Sample table, contains just 2 columns thedate datetime, amount numeric
select cast(datediff(d, number%1000, getdate()) as datetime) as thedate, number as amount
into testtable
from master..spt_values
The query taking month and year as params
declare #month int, #year int
select #month = 2, #year = 2011
select *
from
(
select
amount,
'Week-' + right(dense_rank() over (order by datepart(wk, thedate)),1) week_in_month
from testtable
where thedate >= cast(#year*10000+#month*100+1 as char(8))
and thedate < dateadd(m,1,cast(#year*10000+#month*100+1 as char(8)))
) P
pivot (sum(amount) for week_in_month in ([Week-1],[Week-2],[Week-3],[Week-4],[Week-5])) V
Note:
cast(#year*10000+#month*100+1 as char(8)) : first day of month
dateadd(m,1,..) : first day month after

Resources