Joining sql queries - sql

Can you help with these two queries?
Query one:
declare #startdate datetime
declare #enddate datetime
set #datainicio='2014-03-01'
set #datafim='2014-03-03'
select right([Location Code],4) as Vehicle,MIN(CAST(CAST([date]AS DATE) AS DATETIME) +
CAST([entry time]AS TIME)) as DaeaMin,min([Veihicle Kms]) as KmsMin,MAX(CAST(CAST([date]AS DATE) AS DATETIME) +
CAST([entry time]AS TIME)) as DateMax,max([Veihicle Kms])as KmsMax
where quantity>=0 and [Location code] like 'v%' and [item no_]='601.0001' and ([date] between #startdate and #enddate)
group by [Location Code]
Query two:
SELECT Vehicles.Designation as Vehicle,
SUM(Locations.DistanceFromLastLocation)/1000 as
KMS,convert(varchar(10),LocationDate,120) as Date
FROM Locations INNER JOIN Vehicles ON Locations.VehicleId = Vehicles.VehicleId
GROUP BY Vehicles.Designation,LocationDate
I want to join these two query by Vehicle and the date in query two must be between the datemin and datemax from the query one.
Help please Thanks.

Hope this helps and is a little easier to understand than the other answers. Note I have included spelling mistakes ;)
declare #startdate datetime
declare #enddate datetime
set #datainicio='2014-03-01'
set #datafim='2014-03-03'
SELECT *
FROM (
select right([Location Code],4) as Vehicle,MIN(CAST(CAST([date]AS DATE) AS DATETIME) +
CAST([entry time]AS TIME)) as DaeaMin,min([Veihicle Kms]) as KmsMin,MAX(CAST(CAST([date]AS DATE) AS DATETIME) +
CAST([entry time]AS TIME)) as DateMax,max([Veihicle Kms])as KmsMax
FROM YOURTABLE
where quantity>=0 and [Location code] like 'v%' and [item no_]='601.0001' and ([date] between #startdate and #enddate)
group by [Location Code]
) x
INNER JOIN (
SELECT Vehicles.Designation as Vehicle,
SUM(Locations.DistanceFromLastLocation)/1000 as
KMS,convert(varchar(10),LocationDate,120) as Date
FROM Locations INNER JOIN Vehicles ON Locations.VehicleId = Vehicles.VehicleId
GROUP BY Vehicles.Designation,LocationDate
) y
ON x.Vehicle = y.Vehicle
AND y.DATE BETWEEN x.DaeaMin AND x.DateMax

Since you have not mentioned from clause in first query, I assume for first query you are fetching data from 'Locations' table.
Below answer may be useful.
;with temp as
(
SELECT Vehicles.Designation as Vehicle,
sum(Locations.DistanceFromLastLocation)/1000 as KMS,
convert(varchar(10),Locations.LocationDate,120) as Date
FROM Locations
INNER JOIN Vehicles
ON Locations.VehicleId = Vehicles.VehicleId
group by Vehicles.Designation,Locations.LocationDate
)
select right(Locations.[Location Code],4) as Vehicle,
MIN(CAST(CAST([Locations.date]AS DATE) AS DATETIME) + CAST([Locations.entry time]AS TIME))
as DateaMin,
min([Locations.Veihicle Kms]) as KmsMin,
MAX(CAST(CAST([Locations.date]AS DATE) AS DATETIME) + CAST([Locations.entry time]AS TIME))
as DateMax,
max([Locations.Veihicle Kms])as KmsMax
FROM Locations
Inner Join temp on
temp.Vehicle = right([Locations.Location Code],4)
where Locations.quantity>=0
and [Locations.Location code] like 'v%'
and [Locations.item no_]='601.0001'
and ([Locations.date] between #startdate and #enddate)
and temp.[Date] between
MIN(CAST(CAST([Locations.date]AS DATE) AS DATETIME) + CAST([Locations.entry time]AS TIME))
and
MAX(CAST(CAST([Locations.date]AS DATE) AS DATETIME) + CAST([Locations.entry time]AS TIME))

Related

Sub query Count SQL

I have this code I need to have row count off. I tried to count it but comes as Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
Can you help me with row count, thank you.
select count((
select a.GIRIS_ZAMANI, a.CIKIS_ZAMANI, a.PLAKA, a.UCRET, b.KAMERA_ADI
from ARAC_CIKIS a
left join KAMERALAR b
on b.KAMERA_ID = a.CIKIS_KAMERA_ID
where a.CIKIS_ZAMANI between
(select cast(cast(sysutcdatetime() as date) as datetime) + cast('00:00:00' as datetime)) and
(select cast(cast(sysutcdatetime() as date) as datetime) + cast('23:59:59' as datetime)) and
a.UCRET>0
)
)
You can try below -
select count(*)
from
(
select a.GIRIS_ZAMANI, a.CIKIS_ZAMANI, a.PLAKA, a.UCRET, b.KAMERA_ADI from ARAC_CIKIS a left join KAMERALAR b on b.KAMERA_ID = a.CIKIS_KAMERA_ID
where a.CIKIS_ZAMANI between cast(cast(sysutcdatetime() as date) as datetime)
+ cast('00:00:00' as datetime) and cast(cast(sysutcdatetime() as date) as datetime)
+ cast('23:59:59' as datetime)
and a.UCRET>0
) A
Why are you using a subquery?
select count(*)
from ARAC_CIKIS a left join
KAMERALAR k
on bkKAMERA_ID = a.CIKIS_KAMERA_ID
where a.CIKIS_ZAMANI between cast(cast(sysutcdatetime() as date) as datetime) + cast('00:00:00' as datetime) and
cast(cast(sysutcdatetime() as date) as datetime) + cast('23:59:59' as datetime) and
a.UCRET > 0

Data Table with Current Week and Those Dates One Year Ago

I'm trying to create one sql table with the current week's data (always changing) as well as those dates data from the previous year. I have multiple tables that I have to join but am not sure how to create it all into one table. Here is what I have so far:
------- CURRENT YEAR -------
DECLARE
#CURRENTDATE DATE,
#BEGINDATE DATE
SET #CURRENTDATE = CONVERT(DATE,GETDATE()) ---// TODAY'S DATE //---
SET #BEGINDATE = DATEADD(DAY, -7, GETDATE()) ---// A WEEK BEFORE TODAY'S DATE //---
SELECT SALES.*, RECRUITS.Recruits
FROM
(
SELECT
CONVERT(VARCHAR(10), A.[ORDER DATE], 101) AS 'DAY'
, 'Sales Revenue Current Year' = FORMAT(SUM(A.[GRAND TOTAL]) ,'C', 'EN-US')
, 'Comm. Sales Volume Current Year' = FORMAT(sum(a. [QUALIFYING VOLUME]), 'C', 'EN-US')
FROM TABLE1 a
WHERE CONVERT(VARCHAR(10), A.[ORDER DATE], 101) >= #BEGINDATE AND CONVERT(VARCHAR(10), A.[ORDER DATE], 101) < #CURRENTDATE
GROUP BY CONVERT(VARCHAR(10), A.[ORDER DATE], 101)
) SALES,
(
SELECT
CONVERT(VARCHAR(10),a.[start date],101) AS 'DAY'
,count(b.[id number]) as Recruits
from TABLE2 a
left join
TABLE3 b
on a.enroller = b. [id number]
WHERE CONVERT(VARCHAR(10), A.[START DATE], 101) >= #BEGINDATE AND CONVERT(VARCHAR(10), A.[START DATE], 101) < #CURRENTDATE
group by a.[start date]
) RECRUITS
WHERE SALES.DAY = RECRUITS.DAY
I have the same script for the previous year. It is the same except I set the dates to -366 and -373 days. Any help would be great!
You can use multiple dates with an "OR", like below, but a better solution would be to use a date dimensional table, a list of every daily date with things like "WeekOfYear", "WeekOfMonth", "QuarterOfYear", "IsHoliday", etc. Then you can join your date against that table and query "where t1.WeekOfYear = t2.WeekOfYear".
DECLARE
#EndDate DATE = GETDATE() ---// TODAY'S DATE //---
, #StartDate DATE = DATEADD(DAY, -7, GETDATE()) ---// A WEEK BEFORE TODAY'S DATE //---
, #LYStartDate DATE = DATEADD(YEAR, -1, GETDATE()) ---// A YEAR BEFORE TODAY'S DATE //---
, #LYEndDate DATE = DATEADD(DAY, -7, DATEADD(YEAR, -1, GETDATE())) ---// A YEAR AND A WEEK BEFORE TODAY'S DATE //---
SELECT SALES.*, RECRUITS.Recruits
FROM
(
SELECT
'DAY' = CONVERT(VARCHAR(10), A.[ORDER DATE], 101)
, 'Sales Revenue Current Year' = FORMAT(SUM(A.[GRAND TOTAL]) ,'C', 'EN-US')
, 'Comm. Sales Volume Current Year' = FORMAT(sum(a. [QUALIFYING VOLUME]), 'C', 'EN-US')
FROM TABLE1 a
WHERE (
(CAST(A.[ORDER DATE] AS DATE) >= #StartDate AND CAST(A.[ORDER DATE] AS DATE) <= #EndDate)
OR
(CAST(A.[ORDER DATE] AS DATE) >= #LYStartDate AND CAST(A.[ORDER DATE] AS DATE) <= #lyEndDate)
)
GROUP BY CAST(A.[ORDER DATE] AS DATE)
) SALES,
(
SELECT
'DAY' = CAST(a.[start date] AS DATE)
, Recruits = COUNT(b.[id number])
FROM TABLE2 a
LEFT JOIN TABLE3 b
ON a.enroller = b. [id number]
WHERE (
(CAST(A.[START DATE] AS DATE) >= #StartDate AND CAST(A.[ORDER DATE] AS DATE) <= #EndDate)
OR
(CAST(A.[START DATE] AS DATE) >= #lyStartDate AND CAST(A.[ORDER DATE] AS DATE) <= #LYEndDate)
GROUP BY CAST(a.[start date] AS DATE)
) RECRUITS
WHERE SALES.DAY = RECRUITS.DAY

SQL Count with zero values

I want to create a graph for my dataset for the last 24 hours.
I found a solution that works but this is pretty bad since the table I am outer joining cotains every single row in the DB since I am using the (now deprecated) "all" parameter in the group by.
Here is the solution that currently kind of works.
First I declare the date intervals that is 24 hours back in time from now. I declare it twice so I can use it later in the procedure aswell.
Declare #StartDate datetime = dateadd(hour, -24, getdate())
Declare #StartDateProc datetime = dateadd(hour, -24, getdate())
Declare #EndDate datetime = getdate()
I populate the dates into a temp table including a special formated datetsring.
create table #tempTable
(
Date datetime,
DateString varchar(11)
)
while #StartDate <= #EndDate
begin
insert into #tempTable (Date, DateString)
values (#StartDate, convert(varchar(8), #StartDate, 5) + '-' + convert(varchar(2), #StartDate, 108));
SET #StartDate = dateadd(hour,1, #StartDate);
end
This gives me data that looks like this:
Date DateString
---------------------------------------------
2015-12-09 13:59:01.970 09-12-15-13
2015-12-09 14:59:01.970 09-12-15-14
2015-12-09 15:59:01.970 09-12-15-15
2015-12-09 16:59:01.970 09-12-15-16
So what I want is to join my dataset on the matching date string and show the date even if the matching rows is zero.
Here is the rest of the query
select
Date = c.Date,
Amount = sum(c.Amount)
from
DbTable a
outer apply
(select
Date = b.DateString,
Amount = count(*)
from
#tempTable b
where
convert(varchar(8), a.DateColumn, 5) + '-' + convert(varchar(2), a.DateColumn, 108) = b.DateString
group by all
b.DateString) c
where
a.SomeParameter = 'test' and
a.DateColumn >= #StartDateProc and
a.DateColumn <= #EndDate
group by
c.Date
drop table #tempTable
Test to show actual data:
Declare #StartDate datetime = dateadd(hour, -24, getdate())
Declare #EndDate datetime = getdate()
select
dateString = convert(varchar(8),a.DateColumn,5) + '-' + convert(varchar(2),a.DateColumn, 108),
Amount = COUNT(*)
from
DbTable a
where
a.someParameter = 'test' and
a.DateColumn>= dateadd(hour, -24, getdate()) and
a.DateColumn<= getdate()
group by
convert(varchar(8),a.DateColumn,5) + '-' + convert(varchar(2),a.DateColumn, 108)
First output rows:
dateString Amount
09-12-15-14 1
09-12-15-15 1
09-12-15-16 1
09-12-15-17 3
09-12-15-18 1
09-12-15-22 3
09-12-15-23 2
As you can see here there is no data for the times from 19.00 to 21.00. This is how I want the data to be displayed:
dateString Amount
09-12-15-14 1
09-12-15-15 1
09-12-15-16 1
09-12-15-17 3
09-12-15-18 1
09-12-15-19 0
09-12-15-20 0
09-12-15-21 0
09-12-15-22 3
09-12-15-23 2
Normally, this would be approached with left join rather than outer apply. The logic is simple: keep all rows in the first table along with any matching information from the second. This means put the dates table first:
select tt.DateString, count(t.DateColumn) as Amount
from #tempTable tt left join
DbTable t
on convert(varchar(8), t.DateColumn, 5) + '-' + convert(varchar(2), t.DateColumn, 108) = tt.DateString and
t.SomeParameter = 'test'
where tt.Date >= #StartDateProc and
tt.Date <= #EndDate
group by tt.DateString;
In addition, your comparison for the dates seems overly complex, but if it works for you, it works.
The best bet here would be to use DATETIME type itself and not to lose the opportunity to use indexes:
Declare #d datetime = GETDATE()
;WITH cte1 AS(SELECT TOP 25 -1 + ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) h
FROM master..spt_values),
cte2 AS(SELECT DATEADD(hh, -h, #d) AS startdate,
DATEADD(hh, -h + 1, #d) AS enddate
FROM cte1)
SELECT c.startdate, c.enddate, count(*) as amount
FROM cte2 c
LEFT JOIN DbTable a ON a.DateColumn >= c.startdate AND
a.DateColumn < c.enddate AND
a.SomeParameter = 'test'
GROUP BY c.startdate, c.enddate

SQL select, pad with chronological missing months

Notice the 2015-02 and 2015-03 months are missing in the output from the following group by SQL. If there is no data for a month I want to show the month and 0. Anyone know how to go about this?
SELECT convert(char(7), MeterReadDate, 121),count(*)
FROM [myTable]
where (MeterReadDate > dateadd(d,-356,getdate()))
group by convert(char(7), MeterReadDate, 121)
order by convert(char(7), MeterReadDate, 121)
Sample data:
YYYY-MM COUNT
2014-06 23
2014-07 42
2014-08 80
2014-09 92
2014-10 232
2014-11 88
2014-12 8
2015-01 5
2015-04 2
2015-05 1
Still cannot clear the missing rows, here is where I am with it..
DECLARE #StartDate DATETIME = dateadd(m,-12,getdate()), #EndDate DATETIME = getdate(), #DATE DATETIME
DECLARE #TEMP AS TABLE (MeterReadDate datetime)
SET #DATE = #StartDate
WHILE #DATE <= #EndDate
BEGIN
INSERT INTO #TEMP VALUES ( #DATE)
SET #DATE = DATEADD(MONTH,1,#DATE)
END
SELECT convert(char(7), t.MeterReadDate, 121),count(*)
FROM #TEMP m left join
[myTable] t
on convert(char(7), t.MeterReadDate, 121) = convert(char(7), m.MeterReadDate, 121)
where (t.MeterReadDate > dateadd(m,-12,getdate()))
group by convert(char(7), t.MeterReadDate, 121)
order by convert(char(7), t.MeterReadDate, 121)
If you don't want to go beyond your min and max dates of your results then you can do the following:
WITH cte
AS ( SELECT convert(char(7), MeterReadDate, 121) AS [Date], COUNT(*) AS [Count]
FROM [myTable]
WHERE (MeterReadDate > dateadd(d,-356,getdate()))
GROUP by convert(char(7), MeterReadDate, 121)
),
minmax
AS ( SELECT CAST(MIN([Date] + '-01') AS DATE) AS mind ,
CAST(MAX([Date] + '-01') AS DATE) maxd
FROM cte
),
calendar
AS ( SELECT mind ,
CONVERT(CHAR(7), mind, 121) AS cmind
FROM minmax
UNION ALL
SELECT DATEADD(mm, 1, calendar.mind) ,
CONVERT(CHAR(7), DATEADD(mm, 1, calendar.mind), 121)
FROM calendar
CROSS JOIN minmax
WHERE calendar.mind < minmax.maxd
)
SELECT c.cmind AS [Date],
ISNULL(cte.[Count], 0) AS [Count]
FROM calendar c
LEFT JOIN cte ON c.cmind = cte.[Date]
OPTION ( MAXRECURSION 0 )
You need a list of dates/months that covers the entire period. Here is one method using a recursive CTE:
with months as (
select cast(getdate() - 365) as thedate
union all
select date_add(1, month, thedate)
from months
where thedate <= getdate()
)
select convert(char(7), m.thedate, 121) as yyyy-mm, count(t.MeterReadDate)
from months m left join
[myTable] t
on convert(char(7), MeterReadDate, 121) = convert(char(7), m.thedate, 121)
group by convert(char(7), m.thedate, 121)
order by convert(char(7), m.thedate, 121);
The best way to do this would be to join onto a table containing calendar information, one way to do this without actually altering the database schema (and is more dynamic in my opinion) would be to use a table variable and the DATEADD() function.
DECLARE #StartDate DATETIME = '2015-01-01', #EndDate DATETIME = '2015-12-01', #DATE DATETIME
DECLARE #TEMP AS TABLE ([DATE] DATETIME)
SET #DATE = #StartDate
WHILE #DATE <= #EndDate
BEGIN
INSERT INTO #TEMP VALUES (#DATE)
SET #DATE = DATEADD(MONTH,1,#DATE)
END
SELECT * FROM #TEMP
Set #Start and #End to your required dates, then just join onto your results set!
UPDATE:
To extract the date in the format you gave above under "sample data", meaning you would be able to join onto the table, use:
SELECT
CONCAT(YEAR([DATE]),'-',right('0' + cast(month([DATE]) as varchar),2))
FROM #TEMP
LEFT JOIN MyTable ON...

Return All Months & Years Between Date Range - SQL

I'm a bit stumped how I might go about this.
I have a very basic query, that currently returns sales for each product, by year and month.
It is grouping by year/month, and summing up the quantity.
This returns one row for each product/year/month combo where there was a sale.
If there was no sale for a month, then there is no data.
I'd like my query to return one row of data for each product for each year/month in my date range, regardless of whether there was actually an order.
If there was no order, then I can return 0 for that product/year/month.
Below is my example query.
Declare #DateFrom datetime, #DateTo Datetime
Set #DateFrom = '2012-01-01'
set #DateTo = '2013-12-31'
select
Convert(CHAR(4),order_header.oh_datetime,120) + '/' + Convert(CHAR(2),order_header.oh_datetime,110) As YearMonth,
variant_detail.vad_variant_code,
sum(order_line_item.oli_qty_required) as 'TotalQty'
From
variant_Detail
join order_line_item on order_line_item.oli_vad_id = variant_detail.vad_id
join order_header on order_header.oh_id = order_line_item.oli_oh_id
Where
(order_header.oh_datetime between #DateFrom and #DateTo)
Group By
Convert(CHAR(4),order_header.oh_datetime,120) + '/' + Convert(CHAR(2),order_header.oh_datetime,110),
variant_detail.vad_variant_code
You can generate this by using CTE.
You will find information on this article :
http://blog.lysender.com/2010/11/sql-server-generating-date-range-with-cte/
Especially this piece of code :
WITH CTE AS
(
SELECT #start_date AS cte_start_date
UNION ALL
SELECT DATEADD(MONTH, 1, cte_start_date)
FROM CTE
WHERE DATEADD(MONTH, 1, cte_start_date) <= #end_date
)
SELECT *
FROM CTE
Thank your for your suggestions.
I managed to get this working using another method.
Declare #DateFrom datetime, #DateTo Datetime
Set #DateFrom = '2012-01-01'
set #DateTo = '2013-12-31'
select
YearMonthTbl.YearMonth,
orders.vad_variant_code,
orders.qty
From
(SELECT Convert(CHAR(4),DATEADD(MONTH, x.number, #DateFrom),120) + '/' + Convert(CHAR(2),DATEADD(MONTH, x.number, #DateFrom),110) As YearMonth
FROM master.dbo.spt_values x
WHERE x.type = 'P'
AND x.number <= DATEDIFF(MONTH, #DateFrom, #DateTo)) YearMonthTbl
left join
(select variant_Detail.vad_variant_code,
sum(order_line_item.oli_qty_required) as 'Qty',
Convert(CHAR(4),order_header.oh_datetime,120) + '/' + Convert(CHAR(2),order_header.oh_datetime,110) As 'YearMonth'
FROM order_line_item
join variant_detail on variant_detail.vad_id = order_line_item.oli_vad_id
join order_header on order_header.oh_id = order_line_item.oli_oh_id
Where
(order_header.oh_datetime between #DateFrom and #DateTo)
GROUP BY variant_Detail.vad_variant_code,
Convert(CHAR(4),order_header.oh_datetime,120) + '/' + Convert(CHAR(2),order_header.oh_datetime,110)
) as Orders on Orders.YearMonth = YearMonthTbl.YearMonth
This is what I put together. It will certainly need some debugging, but I think that this will lead you in the right direction. I broke up the queries into different parts in order to attempt to make it easier to read. Hope this helps.
DECLARE #dateFrom DATETIME, #dateTo DATETIME
SELECT #dateFrom = MIN(oh_datetime) FROM order_header
SELECT #dateTo = MAX(oh_datetime) FROM order_header
;WITH
y AS
(
SELECT YEAR(#dateFrom) AS [Year]
UNION ALL
SELECT [Year] + 1
FROM y
WHERE
[Year] < YEAR (GETDATE())
),
m AS
(
SELECT 1 AS [Month]
UNION ALL
SELECT [Month] + 1
FROM m
WHERE
[Month] < 12
),
dates AS
(
SELECT
CAST(y.[Year] AS nvarchar(4)) + N'/' + RIGHT(N'00' + CAST(m.[Month] AS nvarchar(2)), 2) AS YearMonth
FROM
y CROSS JOIN m
),
qty AS
(
SELECT
YEAR(oh.oh_datetime) + N'/' + MONTH(oh.oh_datetime) AS YearMonth,
v.vad_variant_code,
oli.oli_qty_required AS Qty
FROM
variant_Detail AS v
INNER JOIN order_line_item AS oli ON oil.oli_vad_id = v.vad_id
INNER JOIN order_header AS oh ON oh.oh_id = oli.oli_oh_id
)
SELECT
d.YearMonth,
qty.vad_variant_code,
SUM(qty.Qty) AS TotalQty
FROM
dates AS d LEFT OUTER JOIN qty
ON d.YearMonth = qty.YearMonth
GROUP BY
d.YearMonth,
qty.vad_variant_code
Here is another twist, if you find all months of a year
;WITH DateYear AS (
SELECT 0 AS num
UNION ALL
SELECT num + 1 FROM DateYear
WHERE num < 11
)
Select FirstDateOfTheMonth, DATENAME(mm,FirstDateOfTheMonth), num from
(SELECT CONVERT(DATE,DATEADD(MONTH,num,'2017')) AS FirstDateOfTheMonth, num from DateYear)
cte
and the result will be
Another twist:
Declare #dateFrom datetime ='2019-03-21', #dateTo datetime ='2019-12-31'
;WITH CTE AS
(
SELECT #dateFrom AS cte_start_date
UNION ALL
SELECT DATEADD(MONTH, 1, cte_start_date)
FROM CTE
WHERE ( DATEADD(MONTH, 1, cte_start_date) <= EOMONTH( #dateTo) )
--or ( DATENAME(MONTH, cte_start_date) =DATENAME(MONTH, #dateTo) and DATENAME(year, cte_start_date) =DATENAME(year, #dateTo) ) )
)
SELECT *
FROM CTE
This below is work for sqlserver 2012 and above to get the last day of the month :-
Select EOMONTH('2020-02-15')