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 9, 2013 10:26 AM


SSC Eights!

SSC Eights!SSC Eights!SSC Eights!SSC Eights!SSC Eights!SSC Eights!SSC Eights!SSC Eights!

Group: General Forum Members
Last Login: Thursday, September 11, 2014 3:32 PM
Points: 977, Visits: 3,357
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 9, 2013 11:04 AM
SSCommitted

SSCommittedSSCommittedSSCommittedSSCommittedSSCommittedSSCommittedSSCommittedSSCommitted

Group: General Forum Members
Last Login: 2 days ago @ 6:38 AM
Points: 1,596, Visits: 6,635
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 9, 2013 1:30 PM


SSC Eights!

SSC Eights!SSC Eights!SSC Eights!SSC Eights!SSC Eights!SSC Eights!SSC Eights!SSC Eights!

Group: General Forum Members
Last Login: Thursday, September 11, 2014 3:32 PM
Points: 977, Visits: 3,357
Thank You Peter

Very handy to know.

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


Mr or Mrs. 500

Mr or Mrs. 500Mr or Mrs. 500Mr or Mrs. 500Mr or Mrs. 500Mr or Mrs. 500Mr or Mrs. 500Mr or Mrs. 500Mr or Mrs. 500

Group: General Forum Members
Last Login: Yesterday @ 5:54 AM
Points: 581, Visits: 2,709
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


-- Alan Burstein



Read this article for best practices on asking questions.
Need to split a string? Try this (Jeff Moden)
Need a pattern-based string spitter? Try this (Dwain Camps)
My blog
Post #1405058
Posted Wednesday, January 9, 2013 6:04 PM


Hall of Fame

Hall of FameHall of FameHall of FameHall of FameHall of FameHall of FameHall of FameHall of FameHall of Fame

Group: General Forum Members
Last Login: Yesterday @ 6:49 PM
Points: 3,648, Visits: 5,326
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





My mantra: No loops! No CURSORs! No RBAR! Hoo-uh!

My thought question: Have you ever been told that your query runs too fast?

My advice:
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?
The path of least resistance can be a slippery slope. Take care that fixing your fixes of fixes doesn't snowball and end up costing you more than fixing the root cause would have in the first place.


Need to UNPIVOT? Why not CROSS APPLY VALUES instead?
Since random numbers are too important to be left to chance, let's generate some!
Learn to understand recursive CTEs by example.
Splitting strings based on patterns can be fast!
Post #1405096
Posted Wednesday, January 9, 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 @ 10:00 AM
Points: 37,099, Visits: 31,650
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."

(play on words) "Just because you CAN do something in T-SQL, doesn't mean you SHOULDN'T." --22 Aug 2013

Helpful Links:
How to post code problems
How to post performance problems
Post #1405166
Posted Wednesday, January 9, 2013 9:57 PM


Hall of Fame

Hall of FameHall of FameHall of FameHall of FameHall of FameHall of FameHall of FameHall of FameHall of Fame

Group: General Forum Members
Last Login: Yesterday @ 6:49 PM
Points: 3,648, Visits: 5,326
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?



My mantra: No loops! No CURSORs! No RBAR! Hoo-uh!

My thought question: Have you ever been told that your query runs too fast?

My advice:
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?
The path of least resistance can be a slippery slope. Take care that fixing your fixes of fixes doesn't snowball and end up costing you more than fixing the root cause would have in the first place.


Need to UNPIVOT? Why not CROSS APPLY VALUES instead?
Since random numbers are too important to be left to chance, let's generate some!
Learn to understand recursive CTEs by example.
Splitting strings based on patterns can be fast!
Post #1405167
Posted Wednesday, January 9, 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 @ 10:00 AM
Points: 37,099, Visits: 31,650
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."

(play on words) "Just because you CAN do something in T-SQL, doesn't mean you SHOULDN'T." --22 Aug 2013

Helpful Links:
How to post code problems
How to post performance problems
Post #1405168
Posted Thursday, January 10, 2013 11:59 AM


Mr or Mrs. 500

Mr or Mrs. 500Mr or Mrs. 500Mr or Mrs. 500Mr or Mrs. 500Mr or Mrs. 500Mr or Mrs. 500Mr or Mrs. 500Mr or Mrs. 500

Group: General Forum Members
Last Login: Yesterday @ 5:54 AM
Points: 581, Visits: 2,709
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.


-- Alan Burstein



Read this article for best practices on asking questions.
Need to split a string? Try this (Jeff Moden)
Need a pattern-based string spitter? Try this (Dwain Camps)
My blog
Post #1405590
Posted Thursday, January 10, 2013 12:19 PM


Mr or Mrs. 500

Mr or Mrs. 500Mr or Mrs. 500Mr or Mrs. 500Mr or Mrs. 500Mr or Mrs. 500Mr or Mrs. 500Mr or Mrs. 500Mr or Mrs. 500

Group: General Forum Members
Last Login: Yesterday @ 5:54 AM
Points: 581, Visits: 2,709
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.


-- Alan Burstein



Read this article for best practices on asking questions.
Need to split a string? Try this (Jeff Moden)
Need a pattern-based string spitter? Try this (Dwain Camps)
My blog
Post #1405596
« Prev Topic | Next Topic »

Add to briefcase 1234»»»

Permissions Expand / Collapse