Sub query Count SQL - 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

Related

How to insert missing rows in a table?

I have a table with the following columns (checkdate datetime, duration int). I have this stored procedure which groups the data per hour.
CREATE PROC [dbo].[last_hours]
#hours int
AS
BEGIN
SELECT
CAST(checkdate as date) AS ForDate,
DATEPART(hour, checkdate ) AS OnHour,
AVG(duration) AS Duration
FROM
pings
WHERE
DATEDIFF(hour, checkdate , GETDATE()) <= #hours
GROUP BY
CAST(checkdate as date),
DATEPART(hour, checkdate )
END
The proc works fine. However I have situations where data for certain hours is not available. In this case I need to add an extra "empty" row for every missing hour before returning the result to the client.
Is it possible to do this in an easy way without resorting to cursors and loops?
this uses recursive cte to generate a list of checkdate and then LEFT JOIN to the table.
CREATE PROC [dbo].[last_hours]
#hours int
AS
BEGIN
WITH hours as
(
SELECT checkdate = DATEADD(hour, -#hours, GETDATE())
UNION ALL
SELECT checkdate = DATEADD(hour, 1, checkdate)
FROM hours
WHERE checkdate < GETDATE()
)
SELECT
CAST(h.checkdate as date) AS ForDate,
DATEPART(hour, h.checkdate ) AS OnHour,
AVG(p.duration) AS Duration
FROM
hours h
LEFT JOIN pings p ON CAST(h.checkdate as date) = CAST(p.checkdate as date)
AND DATEPART(hour, h.checkdate) = DATEPART(hour, p.checkdate)
GROUP BY
CAST(h.checkdate as date),
DATEPART(hour, h.checkdate )
ORDER BY ForDate, OnHour
END

7 day average in SQL Server 2014

I need to modify the following T-SQL statement to include a rolling 7 day average of the revenue.
What do I need to include in the following code to achieve that?
SELECT
CAST(create_dtg AS DATE) DATE,
SUM([agent_rev] + [anchor_rev] + [corp_rev] + [offsite_rev]) AS RevenueTotals,
SUM([media_est_cost] + [other_cost]) AS COSTTOTALS
FROM
[dbo].[dw_rpt_traffic]
WHERE
[create_dtg] >= ( Getdate() - 90 )
--GROUP BY CREATE_DTG
--ORDER BY CREATE_DTG ASC
I also tried using Parttion by, however, this returns the same value as the Revenuetotals.
Select a.dte, a.revenuetotals, a.COSTTOTALS, AVG(A.RevenueTotals) OVER (PARTITION BY a.dte ORDER BY a.dte ROWS 7 PRECEDING) as Day7Avg
from
(
select CAST(CREATE_DTG AS DATE) as dte,
SUM([AGENT_REV]+[ANCHOR_REV]+[CORP_REV]+[OFFSITE_REV]) as RevenueTotals,
SUM([MEDIA_EST_COST]+[OTHER_COST]) as COSTTOTALS
FROM [dbo].[dw_rpt_traffic]
where [CREATE_DTG] >= (GetDate() - 90)
GROUP BY CREATE_DTG
) as A
Group by a.dte, a.revenuetotals, a.COSTTOTALS
order by a.dte
Thanks, Karen
For rolling aggregates I typically use an OVER clause with ROWS [...] PRECEDING [...].
WITH cte
AS ( SELECT x.Date
,x.Revenue
,AVG(x.Revenue) OVER ( ORDER BY x.Date
ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
) AS [MA7]
FROM ( SELECT CAST(t.Date AS DATE) AS [Date]
,SUM(t.Revenue) AS [Revenue]
FROM #tmp t
WHERE CAST(t.Date AS DATE) > CAST(GETDATE() - 96 AS DATE)
GROUP BY CAST(t.Date AS DATE)
) x
)
SELECT c.Date
,c.Revenue
,c.MA7
FROM cte c
WHERE c.Date > CAST(GETDATE() - 90 AS DATE)
ORDER BY c.Date;
The table above was generated with the following:
IF ( OBJECT_ID('tempdb..#tmp') IS NOT NULL )
DROP TABLE #tmp;
CREATE TABLE #tmp
(
[Date] DATETIME
,[Revenue] DECIMAL(18, 2)
);
--
DECLARE #first INT = 0
,#last INT = 200;
WHILE #first < #last
BEGIN
INSERT INTO #tmp
( Date, Revenue )
VALUES ( GETDATE() - #first * 0.5, RAND() * 100000 );
SET #first = #first + 1;
END;
Probably the easiest way uses outer apply:
with rt as (
select CAST(CREATE_DTG AS DATE) as dte,
SUM([AGENT_REV]+[ANCHOR_REV]+[CORP_REV]+[OFFSITE_REV]) as RevenueTotals,
SUM([MEDIA_EST_COST]+[OTHER_COST]) as COSTTOTALS
from [dbo].[dw_rpt_traffic]
where [CREATE_DTG] >= (GetDate() - 90)
)
select rt.*, rolling.avgrt
from rt outer apply
(select avg(rt2.RevenueTotals) as avgrt
from rt rt2
where rt2.dte >= dateadd(day, -6, rt.dte) and
rt2.dte <= rt.dte
) rolling
order by dte;

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

Joining sql queries

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))

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')