Dynamic Group By in SQL Server

I currently have a stored procedure that returns 12 fields from a combination of tables in my SQL Server database.  This table contains data for every day of production for over 1000 wells/facilities, over about 8 years.  I currently pass the stored procedure values for DSID, FieldID, Well_ID, StartDate and EndDate, and it returns individual records for each day for each well in list of wells that meet the criteria.  

I want to modify this query, so that it will return the same fields, but so that the Oil, Gas, and Water fields are summed over a particular period (either by month, quarter, or year), still within the data range determined by StartDate and EndDate.  The stored procedure currently looks like:

ALTER PROCEDURE [dbo].[df_Analysis_Production_by_Well_Facility]

	@DSID integer,
	@FieldID integer, 
	@EntityID integer,
	@StartDate DateTime, 
	@EndDate DateTime

AS
BEGIN
	-- SET NOCOUNT ON added to prevent extra result sets from
	-- interfering with SELECT statements.
	SET NOCOUNT ON;

SET @DSID = ISNULL(@DSID, 0)
SET @FieldID = IsNull(@FieldID, 0)
SET @EntityID = ISNULL(@EntityID, 0)

SELECT WF.DS_ID
, DS.DS_Description AS Data_Source
, WF.FieldID
, WF.FieldName
, P.Entity_ID
, WF.Entity_Name AS Well_Fac_Name
, WF.Bolo_ID
, WF.Entity_Type_Desc AS Well_Fac_Type
, P.docDate
, P.Oil
, P.Gas
, P.Water
FROM vw_Wells_and_Facilities_All as WF
RIGHT JOIN tbl_sysProduction as P ON WF.Entity_ID = P.Entity_ID
LEFT JOIN lst_Data_Sources as DS ON WF.DS_ID = DS.DS_ID
WHERE ((@DSID = 0) OR (WF.DS_ID = @DSID))
AND ((@FieldID = 0) OR (WF.FieldID = @FieldID))
AND ((@EntityID = 0) OR (P.Entity_ID = @EntityID))
AND ((@StartDate IS NULL) OR (P.docDate >= @StartDate))
AND ((@EndDate IS NULL) OR (P.docDate < DATEADD(day, 1, @EndDate)))
ORDER BY WF.FieldName, WF.Entity_Name, P.docDate

END

Open in new window

How can I modify this so that I can pass in an additional parameter and have it group accordingly.  I assume I'm going to have to modify the query so that it builds a dynamic SQL string and then execute that from within the SP.  I know how I would do this in Access, using the Format( ) function with the docDate and a format string that either looks like "yyyy", "yy-q", or "yy-mm", but I'm not sure how to go about that in SQL Server.
LVL 50
Dale FyeAsked:
Who is Participating?
 
Valliappan ANSenior Tech ConsultantCommented:
You may try use these:

select DatePart(QUARTER, mydate)

select DatePart(year, mydate)

SELECT CONVERT(VARCHAR(7), GETDATE(), 111) AS [YYYY/MM]
//have not tried above though.. from some other pages..
0
 
Jim HornMicrosoft SQL Server Developer, Architect, and AuthorCommented:
SQL Server CASE Solutions, scroll down to 'CASE can also be used in the ORDER BY clause'.

>pass in an additional parameter and have it group accordingly.
Define 'group accordingly', not getting that.

An example..
ALTER PROC get_names (@SortColumnName varchar(50)) AS

SELECT name, group_id, is_active
FROM some_table
ORDER BY 
   -- First sort position
   CASE 
      WHEN @SortColumnName='name' THEN name
      WHEN @SortColumnName='group_id' THEN CAST(group_id as varchar(max)) END,
	-- Second sort position
   CASE 
      WHEN @SortColumnName='name' THEN CAST(group_id as varchar(max))
      WHEN @SortColumnName='group_id' THEN name END
GO

Open in new window

0
 
Dale FyeAuthor Commented:
Jim,

group accordingly:  depending on how which value I pass in, I either want to group the data year, quarter, month, or day and sum the Oil, Gas, and Water values over those periods.

In Access, instead of displaying docDate in the SELECT clause, I would use Format(docDate, "yy-mm-dd"), or Format(docDate, "yy-mm") or Format(docDate, "yy-q") or Format(docDate, "yy"), and then SUM() on each of the Oil, Gas, and Water fields.  Then I would need to create a GroupBy clause with all of the other fields, and this same Format() statement.  

So, I'm just not sure how to do the Format() conversion in SQL Server based on a passed in parameter.

From your example above, I'm guessing that I won't need to create a string dynamically, I can simply use a Case statement within the SELECT and the Group By clause.
0
Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
PortletPaulfreelancerCommented:
when using a case expression the result data type will need to be consistent. This might result in issues (e.g. having to sort by date, via a varchar) so it some circumstances just using NULL can be helpful. e.g.

  case when @SortColumnName='name' THEN name ELSE NULL END
, case when @SortColumnName='group_id' THEN group_id ELSE NULL END
0
 
Jim HornMicrosoft SQL Server Developer, Architect, and AuthorCommented:
Still not getting it, but sleep deprivation is likely in play here, and since I'm going to bed and it's Paul's morning on Kiwi Time he can pick it up from here.

I'll throw this out as a last grasp...

>I would use Format(docDate, "yy-mm-dd"), or Format(docDate, "yy-mm") or Format(docDate, "yy-q") or Format(docDate, "yy")
>Then I would need to create a GroupBy clause with all of the other fields, and this same Format() statement.  
Let's make it easy on ourselves, avoid the dynamic part entirely, and pass the query off with the above date expression as a subquery, and then just group on it in the main query, so we only have to do the above expression once.  Something like <total air code>

SELECT a.goo, a.foo, a.boo, a.date_part, SUM(some_total), COUNT(some_count) 
FROM (
SELECT goo, foo, boo, some_total, some_count
Case @par 
   WHEN 'ymd' THEN Format(docDate, "yy-mm-dd")
   WHEN 'ym' THEN Format(docDate, "yy-mm") 
   WHEN 'yq' THEN Format(docDate, "yy-q") 
   WHEN 'y' THEN Format(docDate, "yy") END as date_part
FROM some_table) a
GROUP BY a.goo, a.foo, a.boo, a.date_part

Open in new window

0
 
Dale FyeAuthor Commented:
JIm,

The point is, there is no FORMAT( ) function in SQL Server 2008 R2.  I don't know what SQL SERVER function to call to make those transformations from a date into a string in the format of 'yy-mm-dd', 'yy-mm', 'yy-q', or 'yy'.

It doesn't look like they incorportated FORMAT() in SQL Server until 2012.
0
 
Valliappan ANSenior Tech ConsultantCommented:
FYI, the links and comment that i posted before, was deleted by some admin, saying such links not allowed.
0
 
Jim HornMicrosoft SQL Server Developer, Architect, and AuthorCommented:
Yeah I just did a copy-paste on that one.
You can use a combination of DATEPART and Paul's article on SQL Server Date Styles (formats) using CONVERT()

SELECT convert(varchar, your_date_here ,20) gives you yy-mm-dd
SELECT RIGHT(CAST(DATEPART(year, your_date_here) as char(4)),2)  + '-' + RIGHT('0' + CAST(DATEPART(month, your_date_here) as varchar(2)), 2) gives you yy-mm

I'd give you more, but I'm at a gig where they haven't set me up with SQL yet, so I'll back out to encourage other experts to respond.
0
 
Dale FyeAuthor Commented:
Jim,

I've been playing around with this a bit since I found Paul's article.  Between that, and Valli_an's comments about date part, I've managed to get what I need, but it just amazes me how much work it takes.  You have to wonder why it took MS so long to incorporate this simple function (Format) into SQL Server.
0
 
Dale FyeAuthor Commented:
Thanks, all.

Paul,  why didn't you mention your article on Convert and SQL dates.  Took me a while to find it but that helped as well.

Dale
0
 
PortletPaulfreelancerCommented:
"why didn't you mention your article on Convert and SQL dates."
I wasn't online at the right time :)

Anyway, pleased you found it, and that you found it useful.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.