Click here to monitor SSC
SQLServerCentral is supported by Red Gate Software Ltd.
 
Log in  ::  Register  ::  Not logged in
 
 
 
        
Home       Members    Calendar    Who's On


Add to briefcase 1234»»»

Better Way to Perform this Query Expand / Collapse
Author
Message
Posted Wednesday, January 09, 2013 10:26 AM


Right there with Babe

Right there with BabeRight there with BabeRight there with BabeRight there with BabeRight there with BabeRight there with BabeRight there with BabeRight there with Babe

Group: General Forum Members
Last Login: Today @ 6:46 AM
Points: 790, Visits: 2,259
Hello Everyone
I hope that everyone is having a very good day.

I need to write a query to select row counts, but this seems like a lot of scanning of the rows. Is there a better way to write a query that does this? There are approx 5 million rows in the table

DECLARE @abc int
DECLARE @def int
DECLARE @ghi int
DECLARE @jkl int
DECLARE @mno int
DECLARE @pqr int
DECLARE @stu int
DECLARE @vw int
DECLARE @xzy int


SET @abc = (SELECT COUNT(*) FROM TableName WHERE ColumnName LIKE '%abc%')
SET @def = (SELECT COUNT(*) FROM TableName WHERE ColumnName LIKE '%def%')
SET @ghi = (SELECT COUNT(*) FROM TableName WHERE ColumnName LIKE '%ghi%')
SET @jkl = (SELECT COUNT(*) FROM TableName WHERE ColumnName LIKE '%jkl%')
SET @mno = (SELECT COUNT(*) FROM TableName WHERE ColumnName LIKE '%mno%')
SET @pqr = (SELECT COUNT(*) FROM TableName WHERE ColumnName LIKE '%pqr%')
SET @stu = (SELECT COUNT(*) FROM TableName WHERE ColumnName LIKE '%stu%')
SET @vw = (SELECT COUNT(*) FROM TableName WHERE ColumnName LIKE '%vw%')
SET @xzy = (SELECT COUNT(*) FROM TableName WHERE ColumnName LIKE '%xyz%')

Thank You in advance for all your help, advice and suggestions.

Andrew SQLDBA
Post #1404891
Posted Wednesday, January 09, 2013 11:04 AM
SSCommitted

SSCommittedSSCommittedSSCommittedSSCommittedSSCommittedSSCommittedSSCommittedSSCommitted

Group: General Forum Members
Last Login: Yesterday @ 11:28 PM
Points: 1,561, Visits: 6,105
You can try something like this (requires only a single table scan):

SELECT 
@abc = COUNT(CASE WHEN ColumnName LIKE '%abc%' THEN 1 END),
@def = COUNT(CASE WHEN ColumnName LIKE '%def%' THEN 1 END),
@ghi = COUNT(CASE WHEN ColumnName LIKE '%ghi%' THEN 1 END),
@jkl = COUNT(CASE WHEN ColumnName LIKE '%jkl%' THEN 1 END),
@mno = COUNT(CASE WHEN ColumnName LIKE '%mno%' THEN 1 END),
@pqr = COUNT(CASE WHEN ColumnName LIKE '%pqr%' THEN 1 END),
@stu = COUNT(CASE WHEN ColumnName LIKE '%stu%' THEN 1 END),
@vw = COUNT(CASE WHEN ColumnName LIKE '%vw%' THEN 1 END),
@xzy = COUNT(CASE WHEN ColumnName LIKE '%xyz%' THEN 1 END)
FROM
TableName

Post #1404904
Posted Wednesday, January 09, 2013 1:30 PM


Right there with Babe

Right there with BabeRight there with BabeRight there with BabeRight there with BabeRight there with BabeRight there with BabeRight there with BabeRight there with Babe

Group: General Forum Members
Last Login: Today @ 6:46 AM
Points: 790, Visits: 2,259
Thank You Peter

Very handy to know.

Andrew SQLDBA
Post #1404981
Posted Wednesday, January 09, 2013 3:44 PM


SSC Veteran

SSC VeteranSSC VeteranSSC VeteranSSC VeteranSSC VeteranSSC VeteranSSC VeteranSSC Veteran

Group: General Forum Members
Last Login: Tuesday, May 14, 2013 9:06 AM
Points: 223, Visits: 1,137
AndrewSQLDBA (1/9/2013)
Hello Everyone
I hope that everyone is having a very good day.

I need to write a query to select row counts, but this seems like a lot of scanning of the rows. Is there a better way to write a query that does this? There are approx 5 million rows in the table

DECLARE @abc int
DECLARE @def int
DECLARE @ghi int
DECLARE @jkl int
DECLARE @mno int
DECLARE @pqr int
DECLARE @stu int
DECLARE @vw int
DECLARE @xzy int


SET @abc = (SELECT COUNT(*) FROM TableName WHERE ColumnName LIKE '%abc%')
SET @def = (SELECT COUNT(*) FROM TableName WHERE ColumnName LIKE '%def%')
SET @ghi = (SELECT COUNT(*) FROM TableName WHERE ColumnName LIKE '%ghi%')
SET @jkl = (SELECT COUNT(*) FROM TableName WHERE ColumnName LIKE '%jkl%')
SET @mno = (SELECT COUNT(*) FROM TableName WHERE ColumnName LIKE '%mno%')
SET @pqr = (SELECT COUNT(*) FROM TableName WHERE ColumnName LIKE '%pqr%')
SET @stu = (SELECT COUNT(*) FROM TableName WHERE ColumnName LIKE '%stu%')
SET @vw = (SELECT COUNT(*) FROM TableName WHERE ColumnName LIKE '%vw%')
SET @xzy = (SELECT COUNT(*) FROM TableName WHERE ColumnName LIKE '%xyz%')



Its worth noting that the following is sargable.
LIKE '%abc%'

Question:
Are you really trying to find columnNames with abc in their name, def in their name, etc... Or are you trying to get a count of all columns whose name begins with [a-c] for @abc; a count of names beginning with [d-f] for @def, etc, etc... If that's what you are looking for, you can try the query below. It's a way to pass a variable or parameter to NTILE and do what you are doing dynamically (for the most part, some assembly required).

DECLARE @groups int = 9;
;WITH
asciichar(n,c) AS
( SELECT (65), CHAR(65)
UNION ALL
SELECT n+1, CHAR(n+1) FROM asciichar WHERE n+1<=90),
groups AS
( SELECT NTILE(@groups) OVER (ORDER BY n) AS groupid, * FROM asciichar ),
ntileMatrix AS
( SELECT groupid,
MIN(c) OVER (PARTITION BY groupid)+'-'+
MAX(c) OVER (PARTITION BY groupid) AS [group],
n AS [ASCII],
c AS [CHAR]
FROM groups ),
people AS
( SELECT LEFT(LastName,1) AS c1, LastName+', '+FirstName AS Name
FROM AdventureWorks2008R2.person.person )
SELECT nm.[group], p.Name
FROM ntileMatrix nm
CROSS JOIN people p
WHERE [CHAR]=c1

The code above will produce this (truncated for reading):
group Name
----- -------------------------------------
A-C Abbas, Syed
A-C Abel, Catherine
A-C Abercrombie, Kim
....
Y-Z Zukowski, Jake
Y-Z Zwilling, Michael
Y-Z Zwilling, Michael


You can change it to this:
DECLARE @groups int = 9;
;WITH
asciichar(n,c) AS
( SELECT (65), CHAR(65)
UNION ALL
SELECT n+1, CHAR(n+1) FROM asciichar WHERE n+1<=90),
groups AS
( SELECT NTILE(@groups) OVER (ORDER BY n) AS groupid, * FROM asciichar ),
ntileMatrix AS
( SELECT groupid,
MIN(c) OVER (PARTITION BY groupid)+'-'+
MAX(c) OVER (PARTITION BY groupid) AS [group],
n AS [ASCII],
c AS [CHAR]
FROM groups ),
people AS
( SELECT LEFT(LastName,1) AS c1, LastName+', '+FirstName AS Name
FROM AdventureWorks2008R2.person.person ),
Totals AS
(
SELECT nm.[group], p.Name
FROM ntileMatrix nm
CROSS JOIN people p
WHERE [CHAR]=c1 )
SELECT [group], COUNT([group]) AS groupCount
FROM Totals
GROUP BY [group]

To get this:

group groupCount
----- -----------
A-C 3502
D-F 1111
G-I 2572
J-L 2347
M-O 2061
P-R 3195
S-U 2800
V-X 1552
Y-Z 832


Again, some assembly required for what you are doing....

What's cool is you can change the parameter or variable to dynamically change your groups like so:

DECLARE @groups int = 3;

and get this:

group groupCount
----- -----------
A-I 7185
J-R 7603
S-Z 5184


Edit: Typo's


-- AJB
xmlsqlninja.com
Post #1405058
Posted Wednesday, January 09, 2013 6:04 PM


SSCrazy

SSCrazySSCrazySSCrazySSCrazySSCrazySSCrazySSCrazySSCrazy

Group: General Forum Members
Last Login: Yesterday @ 6:07 PM
Points: 2,340, Visits: 3,167
Alan - That's a very intriguing use of NTILE!

I would recommend, however that you change the way you construct your asciichar table:


;WITH asciichar(n, c) AS (
SELECT n=64+number, CHAR(64+number)
FROM [master].dbo.spt_values Tally
WHERE [Type] = 'P' AND Number BETWEEN 1 AND 26)
SELECT *
FROM asciichar





No loops! No CURSORs! No RBAR! Hoo-uh!

INDEXing a poor-performing query is like putting sugar on cat food. Yeah, it probably tastes better but are you sure you want to eat it?

Need to UNPIVOT? Why not CROSS APPLY VALUES instead?
Since random numbers are too important to be left to chance, let's generate some!
Are you too recursively challenged?
Splitting strings based on patterns can be fast!
Post #1405096
Posted Wednesday, January 09, 2013 9:54 PM


SSC-Dedicated

SSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-Dedicated

Group: General Forum Members
Last Login: Today @ 6:23 AM
Points: 32,903, Visits: 26,784
Alan.B (1/9/2013)
[quote]AndrewSQLDBA (1/9/2013)
Its worth noting that the following is sargable.
LIKE '%abc%'



Did you mean "NOT" SARGable because it sure doesn't look SARGable from here. And, I agree... nice use of NTILE.


--Jeff Moden
"RBAR is pronounced "ree-bar" and is a "Modenism" for "Row-By-Agonizing-Row".

First step towards the paradigm shift of writing Set Based code:
Stop thinking about what you want to do to a row... think, instead, of what you want to do to a column."

For better, quicker answers on T-SQL questions, click on the following...
http://www.sqlservercentral.com/articles/Best+Practices/61537/

For better answers on performance questions, click on the following...
http://www.sqlservercentral.com/articles/SQLServerCentral/66909/
Post #1405166
Posted Wednesday, January 09, 2013 9:57 PM


SSCrazy

SSCrazySSCrazySSCrazySSCrazySSCrazySSCrazySSCrazySSCrazy

Group: General Forum Members
Last Login: Yesterday @ 6:07 PM
Points: 2,340, Visits: 3,167
Jeff Moden (1/9/2013)
Alan.B (1/9/2013)
[quote]AndrewSQLDBA (1/9/2013)
Its worth noting that the following is sargable.
LIKE '%abc%'



Did you mean "NOT" SARGable because it sure doesn't look SARGable from here.


Is that because of the % at the beginning of the string?



No loops! No CURSORs! No RBAR! Hoo-uh!

INDEXing a poor-performing query is like putting sugar on cat food. Yeah, it probably tastes better but are you sure you want to eat it?

Need to UNPIVOT? Why not CROSS APPLY VALUES instead?
Since random numbers are too important to be left to chance, let's generate some!
Are you too recursively challenged?
Splitting strings based on patterns can be fast!
Post #1405167
Posted Wednesday, January 09, 2013 9:58 PM


SSC-Dedicated

SSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-Dedicated

Group: General Forum Members
Last Login: Today @ 6:23 AM
Points: 32,903, Visits: 26,784
Yes.

It would also give the wrong answer, IMHO.


--Jeff Moden
"RBAR is pronounced "ree-bar" and is a "Modenism" for "Row-By-Agonizing-Row".

First step towards the paradigm shift of writing Set Based code:
Stop thinking about what you want to do to a row... think, instead, of what you want to do to a column."

For better, quicker answers on T-SQL questions, click on the following...
http://www.sqlservercentral.com/articles/Best+Practices/61537/

For better answers on performance questions, click on the following...
http://www.sqlservercentral.com/articles/SQLServerCentral/66909/
Post #1405168
Posted Thursday, January 10, 2013 11:59 AM


SSC Veteran

SSC VeteranSSC VeteranSSC VeteranSSC VeteranSSC VeteranSSC VeteranSSC VeteranSSC Veteran

Group: General Forum Members
Last Login: Tuesday, May 14, 2013 9:06 AM
Points: 223, Visits: 1,137
dwain.c (1/9/2013)
Alan - That's a very intriguing use of NTILE!

I would recommend, however that you change the way you construct your asciichar table:


;WITH asciichar(n, c) AS (
SELECT n=64+number, CHAR(64+number)
FROM [master].dbo.spt_values Tally
WHERE [Type] = 'P' AND Number BETWEEN 1 AND 26)
SELECT *
FROM asciichar




Thank you, and thank you. I'm still just learning Windows functions (have been studying them for ~6 months now give or take.) For me it's been easy to find a uses for ROW_NUMBER , RANK and DENSE_RANK but this was a rare case where I found some use for NTILE; this was originally a dynamic SQL query.

I agree that I should have used a tally table. I've been writing CTE's for counting for awhile and can do so while sleeping. I still fumble around with the tally table and, in this case was in a hury to post my code. I just updated my query to include the tally table as you showed above: 303 reads is now 146 reads.


-- AJB
xmlsqlninja.com
Post #1405590
Posted Thursday, January 10, 2013 12:19 PM


SSC Veteran

SSC VeteranSSC VeteranSSC VeteranSSC VeteranSSC VeteranSSC VeteranSSC VeteranSSC Veteran

Group: General Forum Members
Last Login: Tuesday, May 14, 2013 9:06 AM
Points: 223, Visits: 1,137
Jeff Moden (1/9/2013)
Alan.B (1/9/2013)
[quote]AndrewSQLDBA (1/9/2013)
Its worth noting that the following is sargable.
LIKE '%abc%'


Did you mean "NOT" SARGable because it sure doesn't look SARGable from here. And, I agree... nice use of NTILE.


Thank you very much Jeff. One year ago I had never heard of windows functions, set-based SQL, or a tally table. I think I'm starting to get it and hope to someday be able to write queries like you, Dwain, Lynn and others on SSC.

Yes - I meant NOT SARGable.


-- AJB
xmlsqlninja.com
Post #1405596
« Prev Topic | Next Topic »

Add to briefcase 1234»»»

Permissions Expand / Collapse