Fast MDX query for one row per-hierarchy on shared dimension - union

Working on a SSAS multidimensional cube that includes a UserGroups dimension made up of multiple hierarchies. Each hierarchy classifies users as belonging to a particular group or not. Users can belong to more than one group.
Trying to generate a table with one row for each hierarchy in the dimension. The best approach that I have come up with is the following:
WITH
MEMBER [Measures].[Group Name] AS
CASE
WHEN [UserGroups].[Group A].CurrentMember.MemberValue <> 'All' THEN "Group A"
WHEN [UserGroups].[Group B].CurrentMember.MemberValue <> 'All' THEN "Group B"
-- More user groups...
WHEN [UserGroups].[Group T].CurrentMember.MemberValue <> 'All' THEN "Group T"
ELSE "Error"
END
SELECT
{[Members].[Group Name], [Measures].[User Count], [Measures].[Revenue]} ON 0,
Order(
UNION(
[UserGroups].[Group A].&[True] *
{[UserGroups].[Group B].[All]} *
-- More user groups...
{[UserGroups].[Group T].[All]},
[UserGroups].[Group A].[All] *
{[UserGroups].[Group B].&[True]} *
-- More user groups...
{[UserGroups].[Group T].[All]},
-- A bunch more blocks so that there is one for each row.
[UserGroups].[Group A].[All] *
{[UserGroups].[Group B].[All]} *
-- More user groups...
{[UserGroups].[Group T].&[True]}
),
)
ON 1
FROM [Finances];
This succeeds in generating the expected table:
Group Name User Count Revenue
All All ... True Group T 90 1800
... ... ... ... ... ... ...
All True ... All Group B 20 400
True All ... All Group A 10 100
However, the query is very slow. Any given row can be calculated in isolation in about 30 seconds. When combining rows using the UNION statement, each additional row seems to result in an exponential increase in computation time rather than the desired linear increase in computation time.
Why is this increase in time observed?
Is there a way to instruct the underlying engine to compute each row in isolation?
Is there simply a better way to issue this query?

I guess you've already experimented with rearranging the query - if you take UNION(...) out of the SELECT and make it a named SET in a WITH clause does that help?
WITH
SET [RowSet] AS
UNION(
[UserGroups].[Group A].&[True] *
{[UserGroups].[Group B].[All]} *
-- More user groups...
{[UserGroups].[Group T].[All]},
[UserGroups].[Group A].[All] *
{[UserGroups].[Group B].&[True]} *
-- More user groups...
{[UserGroups].[Group T].[All]},
-- A bunch more blocks so that there is one for each row.
[UserGroups].[Group A].[All] *
{[UserGroups].[Group B].[All]} *
-- More user groups...
{[UserGroups].[Group T].&[True]}
)
MEMBER [Measures].[Group Name] AS
CASE
WHEN [UserGroups].[Group A].CurrentMember.MemberValue <> 'All' THEN "Group A"
WHEN [UserGroups].[Group B].CurrentMember.MemberValue <> 'All' THEN "Group B"
-- More user groups...
WHEN [UserGroups].[Group T].CurrentMember.MemberValue <> 'All' THEN "Group T"
ELSE "Error"
END
SELECT
{[Members].[Group Name], [Measures].[User Count], [Measures].[Revenue]} ON 0,
Order(
[RowSet],
)
ON 1
FROM [Finances];
What is the purpose of the ORDER function? I cannot see what you are ordering by?
Again just a shot in the dark but I think sometimes I've noticed differences in efficiency between using UNION and using the + operator - so another option:
WITH
SET [RowSet] AS
{
[UserGroups].[Group A].&[True] *
{[UserGroups].[Group B].[All]} *
-- More user groups...
{[UserGroups].[Group T].[All]}
}
+
{
[UserGroups].[Group A].[All] *
{[UserGroups].[Group B].&[True]} *
-- More user groups...
{[UserGroups].[Group T].[All]}
}
-- A bunch more blocks so that there is one for each row.
+
{
[UserGroups].[Group A].[All] *
{[UserGroups].[Group B].[All]} *
-- More user groups...
{[UserGroups].[Group T].&[True]}
}
MEMBER [Measures].[Group Name] AS
...
...
Apologies I don't have definites - the above are just options that might get lucky!! Best to discuss in as much detail as you can with Greg as he will be able to give you solid advise on possible amendments to the cube design.

Related

How to determine data distribution in SQL Server columns using T-SQL

Can someone show me how to compile code in T-SQL that will allow me to view the distribution of data in columns?
For example in the sample table, there is a column called model. In that column, 50% of the values are Fiestas. I would like to a query that will help determine the distribution of in data in columns.
I have included some sample code to help:
CREATE TABLE #tmpTable
(
registration varchar(50),
make varchar(50),
model varchar(50),
engine_size float
)
INSERT INTO #tmpTable VALUES
('JjFw5a0','SKODA','OCTAVIA',1.8),
('VkfCDpZ','FORD','FIESTA',1.7),
('5E93ZEq','SKODA','OCTAVIA',1.3),
('L2PPN0m','FORD','FIESTA',1.1),
('9xKghxp','FORD','FIESTA',1.5),
('WHShdBm','FORD','FIESTA',1.4),
('TNRHyy7','NISSAN','QASHQAI',1.2),
('6RNX0XG','SKODA','OCTAVIA',1.4),
('tJ9bOD8','FORD','FIESTA',1.1),
('ablFUSC','FORD','FIESTA',1),
('4B7RLYL','MERCEDED_BENZ','E CLASS',1.3),
('tlJiwVY','FORD','FIESTA',1),
('Fb9lcvG','FORD','FIESTA',1.4),
('nW4lqBC','FORD','FIESTA',1.6),
('LggTmL5','HYUNDAI','I20',1),
('2mGgSjS','FORD','FIESTA',1.1),
('IDvOzcM','FORD','FIESTA',1.3),
('JefpXK2','FORD','FIESTA',1.5),
('0h1uWfZ','MERCEDED_BENZ','E CLASS',1.4),
('ylBoGbV','MERCEDED_BENZ','E CLASS',1.7),
('XzoILDK','VAUXHALL','CORSA',1.8),
('Xhocs1Z','FORD','FIESTA',1.5),
('Lh2yWGa','KIA','RIO',1.5),
('hM5GWA0','FORD','FIESTA',1.3),
('PbpxkFt','FORD','FIESTA',1.7),
('SDHWV2r','FORD','FIESTA',1.2),
('n83Je2D','FORD','FIESTA',1.8),
('sDN0gex','FORD','FIESTA',1.2),
('7EICOZY','KIA','RIO',1.5),
('PUuMmIH','FORD','FIESTA',1),
('HiBwSg2','FORD','FIESTA',1.8),
('1yk1vDm','KIA','RIO',1.7),
('cMpH72R','HYUNDAI','I20',1.1),
('ZgQL0gt','MERCEDED_BENZ','E CLASS',1.3),
('jhpamQG','KIA','RIO',1.1),
('pk0lU2F','VAUXHALL','CORSA',1.4),
('fDCUeq1','FORD','FIESTA',1.1),
('ono5QFC','FORD','FIESTA',1.7),
('VohWwGR','FORD','FIESTA',1.5),
('Hih8dKc','SUZUKI','SWIFT',1.2),
('D2RNn3h','SUZUKI','SWIFT',1.2),
('QaYQulE','FORD','FIESTA',1.1),
('xmQPxAG','FORD','FIESTA',1.8),
('vmTqkTO','FORD','FIESTA',1.2),
('lvUtVUA','MERCEDED_BENZ','E CLASS',1),
('SFoj00d','FORD','FIESTA',1),
('9S6wrWV','MERCEDED_BENZ','E CLASS',1),
('0SBnW0z','FORD','FIESTA',1.1),
('HnDHdfj','MERCEDED_BENZ','E CLASS',1),
('RV7q947','FORD','FIESTA',1.4),
('JZqCtTg','FORD','FIESTA',1.7),
('XVgBwgi','FORD','FIESTA',1.8),
('iqJDsIF','FORD','FIESTA',1.6),
('CMbpRFa','FORD','FIESTA',1.6),
('vF7K5Xg','SUZUKI','SWIFT',1.1),
('3j6XGDH','FORD','FIESTA',1.5),
('ommqugM','FORD','FIESTA',1.1),
('LMQkPnw','NISSAN','QASHQAI',1.4),
('1dKgcdd','FORD','FIESTA',1.5),
('hC8BxiP','MERCEDED_BENZ','E CLASS',1.1),
('wLTWol7','FORD','FIESTA',1.6),
('TY8ChYN','FORD','FIESTA',1.6),
('Gw1CpI8','FORD','FIESTA',1.4),
('L4OPAJq','FORD','FIESTA',1.1),
('6TyYpfi','NISSAN','QASHQAI',1.6),
('ozoOcGL','FORD','FIESTA',1.4),
('6IME19U','FORD','FIESTA',1.4),
('BxpmJO5','FORD','FIESTA',1.4),
('0zc2n5A','FORD','FIESTA',1.3),
('FqbBZE2','FIAT','500',1.7),
('2EkTOTz','FORD','FIESTA',1.4),
('fNBvIvg','MERCEDED_BENZ','E CLASS',1.2),
('u5j4R4S','KIA','RIO',1.4),
('zpWaUZo','FORD','FIESTA',1.1),
('FQPVQYc','NISSAN','QASHQAI',1.7),
('8RBQADq','KIA','RIO',1.7),
('TOz2bcT','HYUNDAI','I20',1.7),
('jebhCex','FORD','FIESTA',1.3),
('cdHA1gL','FORD','FIESTA',1.2),
('FoaN4AT','FORD','FIESTA',1.7),
('atGn288','FORD','FIESTA',1.5),
('es8VNdW','FIAT','500',1.3),
('hDWoMXa','KIA','RIO',1.4),
('Q9C6Br1','KIA','RIO',1.5),
('mFSy4aF','FORD','FIESTA',1.6),
('bbbKnrM','SKODA','OCTAVIA',1.5),
('qY7lz6I','FORD','FIESTA',1),
('8Ch2OeU','VAUXHALL','CORSA',1.3),
('dcWsjJv','VAUXHALL','CORSA',1.3),
('bnnoBPg','SKODA','OCTAVIA',1.8),
('mvDyYkK','FORD','FIESTA',1.4),
('KpWDYap','FORD','FIESTA',1.3),
('7EK9K4z','FORD','FIESTA',1.3),
('ZPLHtlP','FORD','FIESTA',1.6),
('4EpYeSB','FORD','FIESTA',1.6),
('O1eZ20M','FORD','FIESTA',1),
('WfVntKk','FORD','FIESTA',1.7),
('6VlkBdi','FORD','FIESTA',1.1),
('hFQfKjk','KIA','RIO',1.4),
('3Y4njNP','KIA','RIO',1),
('3UuNqG0','FORD','FIESTA',1.7),
('qpvMYAu','FORD','FIESTA',1.1),
('NCYJUqx','FORD','FIESTA',1.3),
('M0AvWzg','FORD','FIESTA',1.6),
('XbVmtFf','FORD','FIESTA',1.3),
('l8qZy0H','SKODA','OCTAVIA',1.3),
('EDUbxaU','MERCEDED_BENZ','E CLASS',1.6),
('nWLd82o','FORD','FIESTA',1.7),
('4AkoyWx','FORD','FIESTA',1),
('nOoO25v','FORD','FIESTA',1.3),
('VAm5aV8','NISSAN','QASHQAI',1.4),
('zbd3cie','FORD','FIESTA',1.5),
('hyAN71W','NISSAN','QASHQAI',1),
('FxACHDf','FIAT','500',1.7),
('wOZdaeV','FORD','FIESTA',1.6),
('gfxZl99','VAUXHALL','CORSA',1.1),
('06HhwEJ','SKODA','OCTAVIA',1.7),
('PCTgYiG','KIA','RIO',1.7),
('U54WXZQ','KIA','RIO',1.6),
('FHgrRiF','FORD','FIESTA',1.6),
('R3jP73p','SKODA','OCTAVIA',1.5),
('etVPKX9','SUZUKI','SWIFT',1.1),
('BE3yReB','FORD','FIESTA',1.7),
('zXmX878','FORD','FIESTA',1.6),
('wdM3P2m','FORD','FIESTA',1.7),
('tb727BM','FORD','FIESTA',1.1)
SELECT * FROM #tmpTable
You can apply a Windowed Aggregate to get the overall count:
SELECT make
, model
, count(*) as cnt -- count per Model
, cast(count(*) * 100.0 -- compared to all counts
/ sum(count(*))
over () as dec(5,2)) as distribution
FROM #tmptable
group by make
, model
order by distribution desc;
See fiddle
If you want the percentage of the Model for each Make you need to add PARTITION BY:
SELECT make
, model
, count(*) as cnt -- count per Model
, cast(count(*) * 100.0
/ sum(count(*)) -- compared to all counts per Make
over (partition by Make) as dec(5,2)) as distribution
FROM #tmptable
group by make
, model
order by make, distribution desc;
You can use conditional aggregation to get the ratio of the count of Ford Fiestas and the total count.
SELECT 100.0
* count(CASE
WHEN make = 'FORD'
AND model = 'FIESTA' THEN
1
END)
/ count(*)
FROM #tmptable;
Edit:
If you want the figures for all car models you can simply aggregate and group to get the count for each car model and divide that by the total count which you can get via a subquery.
SELECT make,
model,
100.0
* count(*)
/ (SELECT count(*)
FROM #tmptable)
FROM #tmptable
GROUP BY make,
model;

Adding conditions at the WHERE clause gives more results

I use SqlServer. I have a table with lots of columns the importants of which are:
· User_name
· Partition - Date in xxxx-xx-xx format
· Game - a string that works as an ID
· Credits - A number
· Bet - Another number
· Prize - Another number
· Num_Spins - Another number
I wrote a query to select of those the ones that interest me given a specific date.
Select distinct CONCAT(User_Name, DATALENGTH(User_Name)) as User_name, Partition, Game, Bet, Num_spins, Credits, Prize
from ***
where Partition>='2019-09-01' and Partition<'2019-11-17' and Bet>0 and credits is not null
and User_Name IN (Select distinct userName from *** where GeoIpCountryCode='ES')
I wish I could make that a view or something, but unfortunately I don't have the privileges to do so. Therefore, I do a subquery from it:
I want to find out of those rows, the ones whose numbers follow a certain math result: (Credits+Bet-Prize) > 100000 and num_spins>5
Select user_name, partition, count(Game) as difMachines
FROM
(
Select distinct CONCAT(User_Name, DATALENGTH(User_Name)) as User_name, Partition, Game, Bet, Num_spins, Credits, Prize
from ***
where Partition>='2019-09-01' and Partition<'2019-11-17' and Bet>0 and credits is not null
and User_Name IN (Select distinct userName from *** where GeoIpCountryCode='ES')
) as A
where
(Credits+Bet-Prize) > 100000 and num_spins>5
group by User_Name, Partition;
Now, I got all the information I need. I run the last query, to group_by date these results so I can analyze them:
Select datepart(week,Partition) as Week, count (distinct user_name) as Users
from (
Select user_name, partition, count(Game) as difMachines
FROM
(
Select distinct CONCAT(User_Name, DATALENGTH(User_Name)) as User_name, Partition, Game, Bet, Num_spins, Credits, Prize
from ***
where Partition>='2019-09-01' and Partition<'2019-11-17' and Bet>0 and credits is not null
and User_Name IN (Select distinct userName from *** where GeoIpCountryCode='ES')
) as A
where
(Credits+Bet-Prize) > 100000 and num_spins>5
group by User_Name, Partition
) as B
Where difMachines=1
group by datepart(week,Partition)
order by Week asc;
I know the query can be optimized, but that's not what troubles me. The problem is that when running this query, I obtain at week 36 17050 users. If I change this line (Credits+Bet-Prize) > 100000 and num_spins>5 for this one (Credits+Bet-Prize) > 100000 (so, I purely remove the num_spins>5 part), I get 16800 users instead.
To sum up, I get more results by being more restrictive in my query. That does not make sense to me. Someone please can help? Head me to the right direction or something?
Thank you
You are trying to get the count of result set with this filter diffmachine=1,isn't?. but if you remove the filter num_spins>5 then count will increase for diffmachine greater than 1.here i give an example like yours
Declare #t table
(
[user_name] varchar(5), [partition] date, Game varchar(10),num_spins int
)
insert into #t
select 'a','01nov19','g1',1
union all
select 'a','01nov19','g1',2
union all
select 'a','01nov19','g1',3
union all
select 'a','01nov19','g1',4
union all
select 'a','01nov19','g1',5
union all
select 'a','01nov19','g1',6
union all
select 'b','01nov19','g1',7
select * from
(
select [user_name],[partition],count(game) cnt
from #t
where num_spins>5
group by [user_name],[partition]
)a
where cnt=1

MS SQL If Selected is NULL Run another statement

I have two sql statements,
select * from UserTable where role='HOD'
select * from UserTable where role='Supervisor'
I want the results to be in a way such that if the first statement returns nothing, I want the second statement to run and if first statement returns something, second statement do not need to run. Is there a way to do it, be it in a stored procedure or a SQLQuery?
Executing two queries is more expensive than executing a single one that returns both result sets. It would be cheaper to filter the results on the client.
Even if you return all results in a single query, you can differentiate the two cases. For example, HOD always comes before Supervisor. You could use a ranking function like ROW_NUMBER() to assign a value to each row, depending on whether it matches HOD or Supervisor:
with a as (
select * ,row_number() over (partition by Role order by Role) as rn
from UserTable
where Role in ('HOD','Supervisor')
)
select *
from a
where rn=1
Another option is to combine a query that returns HOD with a query that returns Supervisor if HOD doesn't exist:
select *
from UserTable
where Role ='HOD'
UNION ALL
select *
from UserTable
where Role ='Supervisor'
AND NOT EXISTS (SELECT 1
from UserTable
where Role ='Supervisor')
The performance of both queries can be improved if Role is part of an index. The first query becomes equivalent to a simple index seek if the table has an index that covers all the returned fields. If the query returns only eg, ID, UserName, Role :
with a as (
select * ,row_number() over (partition by Role order by Role) as rn
from UserTable
where Role in ('HOD','Supervisor')
)
select ID,UserName, Role
from a
where rn=1
and the table has a covering index:
CREATE INDEX IX_UserTable_Roles ON UserTable (Role,ID,UserName)
The resulting execution plan is a single INDEX SEEK on the index
Try This
IF EXISTS (
SELECT 1 FROM UserTable WHERE ROLE = 'HOD'
)
BEGIN
SELECT * FROM UserTable WHERE ROLE = 'HOD'
END
ELSE BEGIN
SELECT * FROM UserTable WHERE ROLE = 'Supervisor'
END
This should do :
IF EXISTS(SELECT 1 FRom UserTable where role='HOD')
Begin
select * from UserTable where role='HOD'
END
ELSE BEGIN
select * from UserTable where role='Supervisor'
END
If you are using Transact SQL then a good page to read about this is https://learn.microsoft.com/en-us/sql/t-sql/language-elements/if-else-transact-sql
In the Transact SQL instance, the general version of what you are looking for is;
IF Boolean_expression
{ sql_statement | statement_block }
[ ELSE
{ sql_statement | statement_block } ]

T-SQL Grouping Sets of Information

I have a problem which my limited SQL knowledge is keeping me from understanding.
First the problem:
I have a database which I need to run a report on, it contains configurations of a users entitlements. The report needs to show a distinct list of these configurations and a count against each one.
So a line in my DB looks like this:
USER_ID SALE_ITEM_ID SALE_ITEM_NAME PRODUCT_NAME CURRENT_LINK_NUM PRICE_SHEET_ID
37715 547 CultFREE CultPlus 0 561
the above line is one row of a users configuration, for every user ID there can be 1-5 of these lines. So the definition of a configuration is multiple rows of data sharing a common User ID with variable attributes..
I need to get a distinct list of these configurations across the whole table, leaving me just one configuration set for every instance where > 1 has that configuration and a count of instances of that configuration.
Hope this is clear?
Any ideas?!?!
I have tried various group by's and unions, also the grouping sets function to no avail.
Will be very greatful if anyone can give me some pointers!
Ouch that hurt ...
Ok so problem:
a row represents a configurable line
users may be linked to more than 1 row of configuration
configuration rows when grouped together form a configuration set
we want to figure out all of the distinct configuration sets
we want to know what users are using them.
Solution (its a bit messy but the idea is there, copy and paste in to SQL management studio) ...
-- ok so i imported the data to a table named SampleData ...
-- 1. import the data
-- 2. add a new column
-- 3. select all the values of the config in to the new column (Configuration_id)
--UPDATE [dbo].[SampleData]
--SET [Configuration_ID] = SALE_ITEM_ID + SALE_ITEM_NAME + [PRODUCT_NAME] + [CURRENT_LINK_NUM] + [PRICE_SHEET_ID] + [Configuration_ID]
-- 4. i then selected just the distinct values of those and found 6 distinct Configuration_id's
--SELECT DISTINCT [Configuration_ID] FROM [dbo].[SampleData]
-- 5. to make them a bit easier to read and work with i gave them int values instead
-- for me it was easy to do this manually but you might wanna do some trickery here to autonumber them or something
-- basic idea is to run the step 4 statement but select into a new table then add a new primary key column and set identity spec on it
-- that will generate u a bunch of incremental numbers for your config id's so u can then do something like ...
--UPDATE [dbo].[SampleData] sd
--SET Configuration_ID = (SELECT ID FROM TempConfigTable WHERE Config_ID = sd.Configuration_ID)
-- at this point you have all your existing rows with a unique ident for the values combined in each row.
-- so for example in my dataset i have several rows where only the user_id has changed but all look like this ...
--SALE_ITEM_ID SALE_ITEM_NAME PRODUCT_NAME CURRENT_LINK_NUM PRICE_SHEET_ID Configuration_ID
--54101 TravelFREE TravelPlus 0 56101 1
-- now you have a config id you can start to work on building sets up ...
-- each user is now matched with 1 or more config id
-- 6. we use a CTE (common table expression) to link the possibles (keeps the join small) ...
--WITH Temp (ConfigID)
--AS
--(
-- SELECT DISTINCT SD.Configuration_Id --SD2.Configuration_Id, SD3.Configuration_Id, SD4.Configuration_Id, SD5.Configuration_Id,
-- FROM [dbo].[SampleData] SD
--)
-- this extracts all the possible combinations using the CTE
-- on the basis of what you told me, max rows per user is 6, in the result set i have i only have 5 distinct configs
-- meaning i gain nothing by doing a 6th join.
-- cross joins basically give you every combination of unique values from the 2 tables but we joined back on the same table
-- so its every possible combination of Temp + Temp (ConfigID + ConfigID) ... per cross join so with 5 joins its every combination of
-- Temp + Temp + Temp + Temp + Temp .. good job temp only has 1 column with 5 values in it
-- 7. uncomment both this and the CTE above ... need to use them together
--SELECT DISTINCT T.ConfigID C1, T2.ConfigID C2, T3.ConfigID C3, T4.ConfigID C4, T5.ConfigID C5
--INTO [SETS]
--FROM Temp T
--CROSS JOIN Temp T2
--CROSS JOIN Temp T3
--CROSS JOIN Temp T4
--CROSS JOIN Temp T5
-- notice the INTO clause ... this dumps me out a new [SETS] table in my db
-- if i go add a primary key to this and set its ident spec i now have unique set id's
-- for each row in the table.
--SELECT *
--FROM [dbo].[SETS]
-- now here's where it gets interesting ... row 1 defines a set as being config id 1 and nothing else
-- row 2 defines set 2 as being config 1 and config 2 and nothing else ... and so on ...
-- the problem here of course is that 1,2,1,1,1 is technically the same set as 1,1,1,2,1 from our point of view
-- ok lets assign a set to each userid ...
-- 8. first we pull the distinct id's out ...
--SELECT DISTINCT USER_ID usr, null SetID
--INTO UserSets
--FROM SampleData
-- now we need to do bit a of operating on these that's a bit much for a single update or select so ...
-- 9. process findings in a loop
DECLARE #currentUser int
DECLARE #set int
-- while theres a userid not linked to a set
WHILE EXISTS(#currentUser = SELECT TOP 1 usr FROM UserSets WHERE SetId IS NULL)
BEGIN
-- figure out a set to link it to
SET #set = (
SELECT TOP 1 ID
FROM [SETS]
-- shouldn't really do this ... basically need to refactor in to a table variable then compare to that
-- that way the table lookup on ur main data is only 1 per User_id
WHERE C1 IN (SELECT DISTINCT Configuration_id FROM SampleData WHERE USER_ID = #currentUser)
AND C2 IN (SELECT DISTINCT Configuration_id FROM SampleData WHERE USER_ID = #currentUser)
AND C3 IN (SELECT DISTINCT Configuration_id FROM SampleData WHERE USER_ID = #currentUser)
AND C4 IN (SELECT DISTINCT Configuration_id FROM SampleData WHERE USER_ID = #currentUser)
AND C5 IN (SELECT DISTINCT Configuration_id FROM SampleData WHERE USER_ID = #currentUser)
)
-- hopefully that worked
IF(#set IS NOT NULL)
BEGIN
-- tell the usersets table
UPDATE UserSets SET SetId = #set WHERE usr = #currentUser
set #set = null
END
ELSE -- something went wrong ... set to 0 to prevent endless loop but any userid linked to set 0 is a problem u need to look at
UPDATE UserSets SET SetId = 0 WHERE usr = #currentUser
-- and round we go again ... until we are done
END
SELECT
USER_ID,
SALE_ITEM_ID, ETC...,
COUNT(*) WhateverYouWantToNameCount
FROM TableNAme
GROUP BY USER_ID

Anyway to get a value similar to ##ROWCOUNT when TOP is used?

If I have a SQL statement such as:
SELECT TOP 5
*
FROM Person
WHERE Name LIKE 'Sm%'
ORDER BY ID DESC
PRINT ##ROWCOUNT
-- shows '5'
Is there anyway to get a value like ##ROWCOUNT that is the actual count of all of the rows that match the query without re-issuing the query again sans the TOP 5?
The actual problem is a much more complex and intensive query that performs beautifully since we can use TOP n or SET ROWCOUNT n but then we cannot get a total count which is required to display paging information in the UI correctly. Presently we have to re-issue the query with a #Count = COUNT(ID) instead of *.
Whilst this doesn't exactly meet your requirement (in that the total count isn't returned as a variable), it can be done in a single statement:
;WITH rowCTE
AS
(
SELECT *
,ROW_NUMBER() OVER (ORDER BY ID DESC) AS rn1
,ROW_NUMBER() OVER (ORDER BY ID ASC) AS rn2
FROM Person
WHERE Name LIKE 'Sm%'
)
SELECT *
,(rn1 + rn2) - 1 as totalCount
FROM rowCTE
WHERE rn1 <=5
The totalCount column will have the total number of rows matching the where filter.
It would be interesting to see how this stacks up performance-wise against two queries on a decent-sized data-set.
you'll have to run another COUNT() query:
SELECT TOP 5
*
FROM Person
WHERE Name LIKE 'Sm%'
ORDER BY ID DESC
DECLARE #r int
SELECT
#r=COUNT(*)
FROM Person
WHERE Name LIKE 'Sm%'
select #r
Something like this may do it:
SELECT TOP 5
*
FROM Person
cross join (select count(*) HowMany
from Person
WHERE Name LIKE 'Sm%') tot
WHERE Name LIKE 'Sm%'
ORDER BY ID DESC
The subquery returns one row with one column containing the full count; the cross join includes it with all rows returned by the "main" query"; and "SELECT *" would include new column HowMany.
Depending on your needs, the next step might be to filter out that column from your return set. One way would be to load the data from the query into a temp table, and then return just the desired columns, and get rowcount from the HowMany column from any row.

Resources