Select data for running total graph using Transact SQL - sql

I have a table with following structure:
AuthorId, FollowersNumber, PublishDate, ...
What I need is to draw graph of a running total of FollowersNumber by periods. Tricky thing is that every author is counted only once. For example for following table:
AuthorId, FollowersNumber, PublishDate
1 100 '2013-01-01'
2 200 '2013-01-01'
3 200 '2013-01-02'
2 100 '2013-01-02'
4 60 '2013-01-03'
1 30 '2013-01-03'
Result must be:
2013-01-01 - 300 (100+200)
2013-01-02 - 500 (300+200)
2013-01-03 - 560 (500+60)
Now my SQL looks like (simplified):
SELECT 0, SUM (q.FollowersNumber) AS Y FROM
(SELECT FollowersNumber FROM dbo.Aggregate p WITH (NOLOCK) WHERE p.PublishDate BETWEEN #CurrentPeriod_0_Start AND #CurrentPeriod_0_End AND p.AuthorId not IN
(SELECT AuthorId FROM dbo.Aggregate WITH (NOLOCK) WHERE PublishDate BETWEEN #PreviousPeriod_0_Start AND #PreviousPeriod_0_End)) AS q
UNION
SELECT 1, SUM (q.FollowersNumber) AS Y FROM
(SELECT FollowersNumber FROM dbo.Aggregate p WITH (NOLOCK) WHERE p.PublishDate BETWEEN #CurrentPeriod_1_Start AND #CurrentPeriod_1_End AND p.AuthorId not IN
(SELECT AuthorId FROM dbo.Aggregate WITH (NOLOCK) WHERE PublishDate BETWEEN #PreviousPeriod_1_Start AND #PreviousPeriod_1_End)) AS q
etc.
After getting that data I count running total of FollowersNumber in C# code.
This query is monstrous and runs slow.
Is there any way to make it faster?

http://sqlfiddle.com/#!3/ff2cf/4
Get Totals history By dates. I don't understand your parameters in query

Possible this be helpful for you -
DECLARE #temp TABLE
(
AuthorId INT
, FollowersNumber INT
, PublishDate DATETIME
)
INSERT INTO #temp (AuthorId, FollowersNumber, PublishDate)
VALUES
(1, 100, '20130101'),
(2, 200, '20130101'),
(3, 200, '20130102'),
(2, 100, '20130102'),
(4, 60, '20130103'),
(1, 30, '20130103')
DECLARE
#CurrentPeriod_0_Start DATETIME
, #PreviousPeriod_0_Start DATETIME
, #CurrentPeriod_0_End DATETIME
, #PreviousPeriod_0_End DATETIME
, #CurrentPeriod_1_Start DATETIME
, #PreviousPeriod_1_Start DATETIME
, #CurrentPeriod_1_End DATETIME
, #PreviousPeriod_1_End DATETIME
SELECT 0, Y = SUM(p.FollowersNumber)
FROM #temp p
WHERE p.PublishDate BETWEEN #CurrentPeriod_0_Start AND #CurrentPeriod_0_End
AND NOT EXISTS(
SELECT 1
FROM #temp p2
WHERE p2.PublishDate BETWEEN #PreviousPeriod_0_Start AND #PreviousPeriod_0_End
AND p2.AuthorId = p.AuthorId
)
UNION ALL
SELECT 1, Y = SUM(p.FollowersNumber)
FROM #temp p
WHERE p.PublishDate BETWEEN #CurrentPeriod_1_Start AND #CurrentPeriod_1_End
AND NOT EXISTS(
SELECT 1
FROM #temp p2
WHERE p2.PublishDate BETWEEN #PreviousPeriod_1_Start AND #PreviousPeriod_1_End
AND p2.AuthorId = p.AuthorId
)

You can use this query instead of yours.
I wrote this query using CTE in SQL Server. I tested it on your data sample and worked fine.
WITH
RANKINGTABLE AS(
SELECT [AUTHORID]
,[FOLLOWERSNUMBER]
,[PUBLISHDATE]
,DENSE_RANK() OVER(PARTITION BY AUTHORID ORDER BY PUBLISHDATE) IRANK
FROM [TESTQUERY].[DBO].[AGGREGATE]
),
DAYSUM AS(
SELECT PUBLISHDATE, SUM([FOLLOWERSNUMBER]) DATESUM
FROM RANKINGTABLE
WHERE IRANK = 1
GROUP BY PUBLISHDATE
)
SELECT DS1.PUBLISHDATE,
(SELECT SUM(DS2.DATESUM) FROM DAYSUM DS2 WHERE DS2.PUBLISHDATE <= DS1.PUBLISHDATE) PTOTAL
FROM DAYSUM DS1

You can try this
SELECT 1, SUM(CASE WHEN PublishDate BETWEEN #PreviousPeriod_0_Start AND #PreviousPeriod_0_End
THEN NULL ELSE CASE WHEN PublishDate BETWEEN #CurrentPeriod_0_Start AND #CurrentPeriod_0_End
THEN FollowersNumber
END
END
) AS Y
FROM dbo.Aggregate WITH(NOLOCK)
UNION ALL
SELECT 0, SUM(CASE WHEN PublishDate BETWEEN #PreviousPeriod_1_Start AND #PreviousPeriod_1_End
THEN NULL ELSE CASE WHEN PublishDate BETWEEN #CurrentPeriod_1_Start AND #CurrentPeriod_1_End
THEN FollowersNumber
END
END
) AS Y
FROM dbo.Aggregate WITH(NOLOCK)
etc.

Related

SQL query to find all rows with same timestamp + or - one second

Row 3 in the following table is a duplicate. I know this because there is another row (row 5) that was created by the same user less than one second earlier.
row record created_by created_dt
1 5734 '00E759CF' '2020-06-05 19:59:36.610'
2 9856 '1E095CBA' '2020-06-05 19:57:31.207'
3 4592 '1E095CBA' '2020-06-05 19:54:41.930'
4 7454 '00E759CF' '2020-06-05 19:54:41.840'
5 4126 '1E095CBA' '2020-06-05 19:54:41.757'
I want a query that returns all rows created by the same user less than one second apart.
Like so:
row record created_by created_dt
1 4592 '1E095CBA' '2020-06-05 19:54:41.930'
2 4126 '1E095CBA' '2020-06-05 19:54:41.757'
This is what I have so far:
SELECT DISTINCT a1.*
FROM table AS a1
LEFT JOIN table AS a2
ON a1.created_by = a2.created_by
AND a1.created_dt > a2.created_dt
AND a1.created_dt <= DATEADD(second, 1, a2.created_dt)
WHERE a1.created_dt IS NOT NULL
AND a.created_dt IS NOT NULL
This is what finally did the trick:
SELECT
a.*
FROM table a
WHERE EXISTS (SELECT TOP 1
*
FROM table a1
WHERE a1.created_by = a.created_by
AND ABS(DATEDIFF(SECOND, a.created_dt, a1.created_dt)) < 1
AND a.created_dt <> a1.created_dt)
ORDER BY created_dt DESC
You could use exists:
select t.*
from mytable t
where exists(
select 1
from mytable t1
where
t1.created_by = t.created_by
and abs(datediff(second, t.created_dt, t1.created_dt)) < 1
)
How about something like this
SELECT DISTINCT a1.*
FROM #a1 AS a1
LEFT JOIN #a1 AS a2 ON a1.[Created_By] = a2.[Created_By]
AND a1.[Record] <> a2.[Record]
WHERE ABS(DATEDIFF(SECOND, a1.[Created_Dt], a2.[Created_Dt])) < 1
Here is the sample query I used to verify the results.
DECLARE #a1 TABLE (
[Record] INT,
[Created_By] NVARCHAR(10),
[Created_Dt] DATETIME
)
INSERT INTO #a1 VALUES
(5734, '00E759CF', '2020-06-05 19:59:36.610'),
(9856, '1E095CBA', '2020-06-05 19:57:31.207'),
(4592, '1E095CBA', '2020-06-05 19:54:41.930'),
(7454, '00E759CF', '2020-06-05 19:54:41.840'),
(4126, '1E095CBA', '2020-06-05 19:54:41.757')
SELECT DISTINCT a1.*
FROM #a1 AS a1
LEFT JOIN #a1 AS a2 ON a1.[Created_By] = a2.[Created_By]
AND a1.[Record] <> a2.[Record]
WHERE ABS(DATEDIFF(SECOND, a1.[Created_Dt], a2.[Created_Dt])) < 1
I would suggest lead() and lag() instead of self-joins:
select t.*
from (select t.*,
lag(created_dt) over (partition by created_dt) as prev_cd,
lead(created_dt) over (partition by created_dt) as next_cd
from t
) t
where created_dt < dateadd(second, 1, prev_created_dt) or
created_dt > dateadd(second, -1, next_created_dt)

How to find spike in data using SQL?

Say I have the following schema:
SENSOR
--------------
ID (numeric)
READ_DATE (date)
VALUE (numeric)
I want to find spikes in data that lasts at least X amount of days. We take 1 reading from the sensor only once per day so ID and READ_DATE are pretty much interchangeable in terms of uniqueness.
For example I have the following records:
1, 2019-01-01, 100
2, 2019-01-02, 1000
3, 2019-01-03, 1500
4, 2019-01-04, 1100
5, 2019-01-05, 500
6, 2019-01-06, 700
7, 2019-01-07, 1500
8, 2019-01-08, 2000
In this example, for X = 2 with VALUE >= 1000, I want to get row 3, 4, 8 because (2, 3), (3, 4), (7, 8) are consecutively >= to 1000.
I am not sure about how to approach this. I was thinking of doing a COUNT window function but don't know how to check whether there are X records >= 1000.
This is about as generic as I think this can get.
First I create some data, using a table variable, but this could be a temporary/ physical table:
DECLARE #table TABLE (id INT, [date] DATE, [value] INT);
INSERT INTO #table SELECT 1, '20190101', 100;
INSERT INTO #table SELECT 2, '20190102', 1000;
INSERT INTO #table SELECT 3, '20190103', 1500;
INSERT INTO #table SELECT 4, '20190104', 1100;
INSERT INTO #table SELECT 5, '20190105', 500;
INSERT INTO #table SELECT 6, '20190106', 700;
INSERT INTO #table SELECT 7, '20190107', 1500;
INSERT INTO #table SELECT 8, '20190108', 2000;
Then I use a CTE (which could be swapped out for a less efficient subquery):
WITH x AS (
SELECT
*,
CASE WHEN [value] >= 1000 THEN 1 END AS spike
FROM
#table)
SELECT
x2.id,
x2.[date],
x2.[value]
FROM
x x1
INNER JOIN x x2 ON x2.id = x1.id + 1
WHERE
x1.spike = 1
AND x2.spike = 1;
This assumes your ids are sequential, if they aren't you would need to join on date instead, which is trickier.
Results:
id date value
3 2019-01-03 1500
4 2019-01-04 1100
8 2019-01-08 2000
Okay, this isn't Postgres, and it isn't very generic (recursive CTE), but it seems to work??
DECLARE #spike_length INT = 3;
WITH x AS (
SELECT
*,
CASE WHEN [value] >= 1000 THEN 1 ELSE 0 END AS spike
FROM
#table),
y AS (
SELECT
x.id,
x.[date],
x.[value],
x.spike AS spike_length
FROM
x
WHERE
id = 1
UNION ALL
SELECT
x.id,
x.[date],
x.[value],
CASE WHEN x.spike = 0 THEN 0 ELSE y.spike_length + 1 END
FROM
y
INNER JOIN x ON x.id = y.id + 1)
SELECT * FROM y WHERE spike_length >= #spike_length;
Results:
id date value spike_length
4 2019-01-04 1100 3
You can approach this as a gaps-and-islands problem -- finding consecutive values above the threshold. The following gets the first date of such sequences:
select s.read_date
from (select s.*,
row_number() over (order by date) as seqnum
from sensor s
where value >= 1000
) s
group by (date - seqnum * interval '1 day')
having count(*) >= 2;
The observation here is that (date - seqnum * interval '1 day') is constant for rows that are adjacent.
You can get the original rows with one more layer of subqueries:
select s.*
from (select s.*, count(*) over (partition by (date - seqnum * interval '1 day') as cnt
from (select s.*,
row_number() over (order by date) as seqnum
from sensor s
where value >= 1000
) s
) s
where cnt >= 2;
I ended up with the following:
-- this parts helps filtering values < 1000 later on
with a as (
select *,
case when value >= 1000 then 1 else 0 end as indicator
from sensor),
-- using the indicator, create a window that calculates the length of the spike
b as (
select *,
sum(indicator) over (order by id asc rows between 2 preceding and current row) as spike
from a)
-- now filter out all spikes < 3
-- (because the window has a size of 3, it can never be larger than 3, so = 3 is okay)
select id, value from b where spike = 3;
This is expanding on #Gordon Linoff's answer, but which I found too complicated.
If you are able to use analytic functions, then you should be able to do something like this to get what you need (I altered your 1000 limit to 1500 else it would have brought back all rows which consecutively add up to 1000 and above)
CREATE TABLE test1 (
id number,
value number
);
insert all
into test1 (id, value) values (1, 100)
into test1 (id, value) values (2, 1000)
into test1 (id, value) values (3, 1500)
into test1 (id, value) values (4, 1100)
into test1 (id, value) values (5, 500)
into test1 (id, value) values (6, 700)
into test1 (id, value) values (7, 1500)
into test1 (id, value) values (8, 2000)
select * from dual;
EDIT - After re-reading again - and from comment - have re-done to answer the actual question! Using 2 lags - one to make sure previous day was 1000 or greater and another to count up how many times has happened for X filtering.
SELECT * FROM
(
SELECT id,
value,
spike,
CASE WHEN spike = 0 THEN 0 ELSE (spike + LAG(spike, 1, 0) OVER (ORDER BY id) + 1) END as SPIKE_LENGTH
FROM (
select id,
value,
CASE WHEN LAG(value, 1, 0) OVER (ORDER BY id) >= 1000 AND value >= 1000 THEN 1 ELSE 0 END AS SPIKE
from test1
)
)
WHERE spike_length >= 2;
Which returns
ID Value spike spike_length
3 1500 1 2
4 1100 1 3
8 2000 1 2
If you increase the spike length filter to >= 3 - only get ID 4 which is the only ID with 3 over 1000 in a row.

db2 query for multiple cases

I have three queries below (identical except for the first line of the WHERE clauses) that all work perfectly in my script. The first one queries orders for a customer, the 2nd for all orders assigned to a representative and the third are all orders period, across the whole company.
Again, they all work given their respective variables (all variables come from the same page) but I'm trying to fill columns on a table for all 3 cases.
Is there a way I can combine these and create one query that gives me the same values for each respective clause?
So, I would expect all 6 columns returned for one query. This is running on db2 so I don't know the best way to proceed but could I create a larger CASE based query?
//query on orders for this customer
SELECT
count(*) as sales_180Cust,
180/count(*) as velocityCust
FROM orders g
inner join dates i
on g.date1 = i.acyyyymmdd
WHERE g.cust = $customer
AND g.frm = $frm
AND g.cvr = $cvr
AND g.clr = $clr
AND i.aciso between current_Date - 180 DAY AND current_Date;
//orders belonging to representative
SELECT
count(*) as sales_180Rep,
180/count(*) as velocityRep
FROM orders g
inner join dates i
on g.date1 = i.acyyyymmdd
WHERE g.rep = $rep
AND g.frm = $frm
AND g.cvr = $cvr
AND g.clr = $clr
AND i.aciso between current_Date - 180 DAY AND current_Date;
//query across ALL orders
SELECT
count(*) as sales_180Company,
180/count(*) as velocityCompany
FROM orders g
inner join dates i
on g.date1 = i.acyyyymmdd
WHERE g.frm = $frm
AND g.cvr = $cvr
AND g.clr = $clr
AND i.aciso between current_Date - 180 DAY AND current_Date;
This would be another way to do this
WITH CTE AS (
SELECT g.cust
, g.rep
FROM orders g
inner join dates i
on g.date1 = i.acyyyymmdd
WHERE
g.frm = $frm
AND g.cvr = $cvr
AND g.clr = $clr
)
SELECT
count(*) as sales_180Company
, 180/count(*) as velocityCompany
, 'cust' as query
FROM CTE
WHERE cust = $customer
UNION ALL
SELECT
count(*) as sales_180Company
, 180/count(*) as velocityCompany
, 'rep' as query
FROM CTE
WHERE rep = $rep
UNION ALL
SELECT
count(*) as sales_180Company
, 180/count(*) as velocityCompany
, 'all' as query
FROM CTE
which returns e.g.
SALES_180COMPANY VELOCITYCOMPANY QUERY
---------------- --------------- -----
3 60 cust
2 90 rep
5 36 all
select q1.*, q2.*, q3.*
from
(select count(*) as sales_180Cust, 180/count(*) as velocityCust from table(values 1) t(i)) q1
, (select count(*) as sales_180Rep, 180/count(*) as velocityRep from table(values 1, 2) t(i)) q2
, (select count(*) as sales_180Company, 180/count(*) as velocityCompany from table(values 1, 2, 3) t(i)) q3
I amended your FROM and WERE clauses to show the idea.
Lots of ways to do this. UNION would be an obvious way. GROUPING SETs is a bit more clever.
create table orders(date1 int, rep int, cust int,frm int, cvr int, clr int, aci int);
create table dates(acyyyymmdd int, aciso date);
create variable $frm int default 1;
create variable $cvr int default 1;
create variable $clr int default 1;
create variable $customer int default 1;
create variable $rep int default 1;
insert into orders values (1,0,0,1,1,1,1), (1,1,1,1,1,1,1), (1,2,1,1,1,1,1), (1,3,1,1,1,1,1), (1,1,2,1,1,1,1);
insert into dates values (1, current date);
then this
SELECT
count(*) as sales_180Company
, 180/count(*) as velocityCompany
, g.cust
, g.rep
FROM orders g
inner join dates i
on g.date1 = i.acyyyymmdd
WHERE
g.frm = $frm
AND g.cvr = $cvr
AND g.clr = $clr
AND i.aciso between current_Date - 180 DAY AND current_Date
GROUP BY GROUPING SETS ( (), (cust), (rep) )
HAVING (cust = $customer AND rep is null)
OR (cust is null AND rep = $rep)
OR (cust is null AND rep is null)
gives this
SALES_180COMPANY VELOCITYCOMPANY CUST REP
---------------- --------------- ---- ----
5 36 NULL NULL
3 60 1 NULL
2 90 NULL 1
Or this... there are often a multitude of ways to do things in SQL
WITH CTE AS (
SELECT g.cust
, g.rep
FROM orders g
inner join dates i
on g.date1 = i.acyyyymmdd
WHERE
g.frm = $frm
AND g.cvr = $cvr
AND g.clr = $clr
) , CUST AS (
SELECT
count(*) as sales_180Company
, 180/count(*) as velocityCompany
FROM CTE
WHERE cust = $customer
) , REP AS (
SELECT
count(*) as sales_180Company
, 180/count(*) as velocityCompany
FROM CTE
WHERE rep = $rep
) , ALL AS (
SELECT
count(*) as sales_180Company
, 180/count(*) as velocityCompany
FROM CTE
)
SELECT * FROM CUST, REP, ALL
retuning
SALES_180COMPANY VELOCITYCOMPANY SALES_180COMPANY VELOCITYCOMPANY SALES_180COMPANY VELOCITYCOMPANY
---------------- --------------- ---------------- --------------- ---------------- ---------------
3 60 2 90 5 36

How to optimize this query , it is taking time 40 minuts in execution?

select * from non_bidders_report_view
where applicant_category_id =1314
and applicant_status_id not in(10,11)
and partner_id = 4
and applicant_status_id <> 6
and applicant_id not in (
Select apb.applicant_id
from applicant_property_bids apb
inner join applicants a on
a.applicant_id=apb.applicant_id
where to_date(apb.bid_Date) >= to_date('30/4/2012','dd/mm/yyyy')
and to_date(apb.bid_Date) <= to_date('30/4/2015','dd/mm/yyyy')
and a.partner_id = 4 group by apb.applicant_Id
union
select aba.applicant_Id from Archive_Bid_Applicants aba
inner join applicants a on a.applicant_id=aba.applicant_id
where to_date(aba.bid_Date) >= to_date('30/4/2012','dd/mm/yyyy')
and to_date(aba.bid_Date) <= to_date('30/4/2015','dd/mm/yyyy')
and a.partner_id = 4 group by aba.applicant_Id
);
You can try this query:
select * from non_bidders_report_view nb
where applicant_category_id = 1314 and partner_id = 4
and applicant_status_id not in (6, 10, 11)
and not exists (
select 1 from applicant_property_bids abp
join applicants a on a.applicant_id=abp.applicant_id and a.partner_id=4
and abp.bid_Date between date '2012-04-30' and date '2015-04-30'
where abp.applicant_id = nb.applicant_id )
and not exists (
select 1 from archive_bid_applicants aba
join applicants a on a.applicant_id=aba.applicant_id and a.partner_id=4
and aba.bid_Date between date '2012-04-30' and date '2015-04-30'
where aba.applicant_id = nb.applicant_id )
The idea is to get rid of group by and union which seems to be unnecesary here and change not in to not exists.
Alternative solution:
select * from non_bidders_report_view nb
where applicant_category_id = 1314 and partner_id = 4
and applicant_status_id not in (6, 10, 11)
and not exists (
select 1 from (
select applicant_id, bid_date from applicant_property_bids
union all
select applicant_id, bid_date from archive_bid_applicants
) ab
join applicants a on a.applicant_id=ab.applicant_id and a.partner_id=4
and ab.bid_Date between date '2012-04-30' and date '2015-04-30'
where ab.applicant_id = nb.applicant_id )
If you have millions of data then create index on primary key. It will increase your performance. Indexes helps to speed up data retrieval. Create index on all 3 tables.

Assistance with creating SQL query

I'm trying to create a query that only returns rows with objects that have three or more orders in a week's timeframe and are only orders submitted after 9/1/13.
SELECT OrderID, DateSubmitted, ObjectID = i.ObjectID
FROM dbo.Object i
JOIN dbo.Order j
ON i.ObjectID = j.ObjectID
WHERE DateSubmitted >= '9/1/2013'
I just can't figure out how to narrow the results to those objects with three or more orders in a week. I've tried numerous GROUP BY and HAVING clauses with no luck. Any help would be greatly appreciated.
Try:
SELECT ObjectID
FROM dbo.Object i
JOIN dbo.Order j ON J.ObjectID = i.ObjectID
WHERE DateSubmitted >= '9/1/2013'
GROUP BY ObjectID
HAVING COUNT(1) >=3
not sure but i need more info on the tables
best guess is in sql
SELECT count(OrderID), i.ObjectID
FROM dbo.Object i
JOIN dbo.Order j
ON i.ObjectID = j.ObjectID
group by i.ObjectID
having DateSubmitted >= '9/1/2013' and count(OrderID)>2
based on your last comments the query you looking for is very simple. use the DatePart function and find out WEEK of that object's order-date. check the below query. also unless you data base is configured already by default Sunday(int 7) is the First Day set in the SQL server. so you for this query purpose you need to set Monday(int 1) as the first day of Week.
you can check the current setting by executing SELECT ##DATEFIRST
if same object has places 3 or more times for multiple weeks below query is returning that object for each of that week. if you needed only Objects then you can skip weekNumber from result set and do Distinct ObjectID.
Do not forget to Reset the DATEFIRST setting to its original Value at the END.
DECLARE #Object TABLE
(
objectID INT
)
DECLARE #Order TABLE
(
orderID INT
,objectID INT
,DateSubmitted DATE
)
INSERT INTO #Object( objectID )
SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6
INSERT INTO #Order ( orderID, objectID, DateSubmitted )
SELECT 1,1,'10/2/2013'
UNION ALL SELECT 2,1,'10/3/2013'
UNION ALL SELECT 3,1,'10/5/2013'
UNION ALL SELECT 4,1,'10/09/2013'
UNION ALL SELECT 5,1,'10/10/2013'
UNION ALL SELECT 6,1,'10/13/2013'
UNION ALL SELECT 4,2,'10/15/2013'
UNION ALL SELECT 5,2,'10/16/2013'
UNION ALL SELECT 6,2,'10/21/2013'
UNION ALL SELECT 7,3,'09/02/2013'
UNION ALL SELECT 8,3,'09/03/2013'
UNION ALL SELECT 9,3,'09/04/2013'
DECLARE #CurrentDateFirst INT=##DATEFIRST
SET DATEFIRST 1;
SELECT i.objectID,DATEPART(week,DateSubmitted) AS weekNumber
FROM #Object i
JOIN #Order j
ON i.ObjectID = j.ObjectID
WHERE DateSubmitted >= '9/1/2013'
GROUP BY i.objectID,DATEPART(week,DateSubmitted)
HAVING(COUNT(DISTINCT orderID) >= 3)
ORDER BY i.objectID
SET DATEFIRST #CurrentDateFirst
Convoluted, but I think this will get you what you want...
With WeekSets As
(
Select i.ObjectID,
j.DateSubmitted,
j2.OrderID
From dbo.Object i
JOIN dbo.Order j
ON i.ObjectID = j.ObjectID
JOIN dbo.Order j2
On j.DateSubmitted <= j2.DateSubmitted
And j2.DateSubmitted < DateAdd(Day,7,j.DateSubmitted)
And j.ObjectID = j2.ObjectID
WHERE j.DateSubmitted >= '9/1/2013'
), GroupsOfThree As
(
Select ObjectID,
DateSubmitted
From WeekSets
Group By ObjectID,
DateSubmitted
Having Count(OrderID) >= 3
)
Select Distinct j.OrderID,
j.DateSubmitted,
w.ObjectID
From GroupsOfThree g
Join WeekSets w
On g.ObjectID = w.ObjectID
And g.DateSubmitted = w.DateSubmitted
Join dbo.Order j
On w.ObjectID = j.ObjectID
And w.OrderID = j.OrderID