From: Rich on
I need to select the count of the first 3 rows per each group (xID) up to a
count of 3 rows (top 3 rows - order by column x1) where the stat column is
not null. if a group contains more than 3 rows where stat is not null -
ignore the extra rows - only count the first 3 rows in each group

CREATE TABLE #tmp1(rowID int Identity(1,1), xID int, x1 int, stat varchar(1))

INSERT INTO #tmp1
SELECT 1, 1, 'f'
UNION ALL SELECT 1, 2, 'f'
UNION ALL SELECT 1, 3, 'f'
UNION ALL SELECT 1, 4, 'f'
UNION ALL SELECT 2, 1, 'f'
UNION ALL SELECT 2, 2, null
UNION ALL SELECT 2, 3, 'f'
UNION ALL SELECT 2, 4, 'f'
UNION ALL SELECT 3, 1, 'f'
UNION ALL SELECT 3, 2, 'f'
UNION ALL SELECT 3, 3, null

Resulting output to look like this

xID countOfRows, Stat
1 3 'f'
2 2 'f'
3 2 'f'

I have tried a self join but not working out - maybe I don't need a self
join? How can I accomplish this?

Thanks,
Rich
From: SQL Menace on
What about this?

select xID,case when count(*) > 3 then 3 else count(*) end
countOfRows ,[stat]
from #tmp1
where stat is not null
group by xID,[stat]



Denis The SQL Menace
http://www.lessthandot.com/
http://sqlservercode.blogspot.com
http://sqlblog.com/blogs/denis_gobo/default.aspx

On Jul 21, 3:36 pm, Rich <R...(a)discussions.microsoft.com> wrote:
> I need to select the count of the first 3 rows per each group (xID) up to a
> count of 3 rows (top 3 rows - order by column x1) where the stat column is
> not null.  if a group contains more than 3 rows where stat is not null -
> ignore the extra rows - only count the first 3 rows in each group
>
> CREATE TABLE #tmp1(rowID int Identity(1,1), xID int, x1 int, stat varchar(1))
>
> INSERT INTO #tmp1
> SELECT 1, 1, 'f'
> UNION ALL SELECT 1, 2, 'f'
> UNION ALL SELECT 1, 3, 'f'
> UNION ALL SELECT 1, 4, 'f'
> UNION ALL SELECT 2, 1, 'f'
> UNION ALL SELECT 2, 2, null
> UNION ALL SELECT 2, 3, 'f'
> UNION ALL SELECT 2, 4, 'f'
> UNION ALL SELECT 3, 1, 'f'
> UNION ALL SELECT 3, 2, 'f'
> UNION ALL SELECT 3, 3, null
>
> Resulting output to look like this
>
> xID   countOfRows,   Stat
> 1           3                 'f'
> 2           2                 'f'
> 3           2                 'f'
>
> I have tried a self join but not working out - maybe I don't need a self
> join?  How can I accomplish this?
>
> Thanks,
> Rich

From: --CELKO-- on
If we get rid of IDENTITY and go with a proper relational design,
would your table look like this? The constraints and a real key are
important.

CREATE TABLE Foobar
(x_id INTEGER NOT NULL,
x1 INTEGER NOT NULL,
PRIMARY KEY (x_id, x1),
stat VARCHAR(1));

>> I need to select the count of the first 3 rows per each group (x_id) up to a count of 3 rows (top 3 rows - order by column x1) where the stat column is not null. if a group contains more than 3 rows where stat is not null - ignore the extra rows - only count the first 3 rows in each group <<

SELKCT *
FROM (SELECT x_id, x1,
ROW_NUMBER() OVER (PARTITION BY x_id ORDER BY x1)
FROM Foobar
WHERE stat IS NOT NULL)
AS X(x_id, x1, x_place)
WHERE x_place <= 3;

From: Rich on
That worked perfectly! Thank you very much.

"SQL Menace" wrote:

> What about this?
>
> select xID,case when count(*) > 3 then 3 else count(*) end
> countOfRows ,[stat]
> from #tmp1
> where stat is not null
> group by xID,[stat]
>
>
>
> Denis The SQL Menace
> http://www.lessthandot.com/
> http://sqlservercode.blogspot.com
> http://sqlblog.com/blogs/denis_gobo/default.aspx
>
> On Jul 21, 3:36 pm, Rich <R...(a)discussions.microsoft.com> wrote:
> > I need to select the count of the first 3 rows per each group (xID) up to a
> > count of 3 rows (top 3 rows - order by column x1) where the stat column is
> > not null. if a group contains more than 3 rows where stat is not null -
> > ignore the extra rows - only count the first 3 rows in each group
> >
> > CREATE TABLE #tmp1(rowID int Identity(1,1), xID int, x1 int, stat varchar(1))
> >
> > INSERT INTO #tmp1
> > SELECT 1, 1, 'f'
> > UNION ALL SELECT 1, 2, 'f'
> > UNION ALL SELECT 1, 3, 'f'
> > UNION ALL SELECT 1, 4, 'f'
> > UNION ALL SELECT 2, 1, 'f'
> > UNION ALL SELECT 2, 2, null
> > UNION ALL SELECT 2, 3, 'f'
> > UNION ALL SELECT 2, 4, 'f'
> > UNION ALL SELECT 3, 1, 'f'
> > UNION ALL SELECT 3, 2, 'f'
> > UNION ALL SELECT 3, 3, null
> >
> > Resulting output to look like this
> >
> > xID countOfRows, Stat
> > 1 3 'f'
> > 2 2 'f'
> > 3 2 'f'
> >
> > I have tried a self join but not working out - maybe I don't need a self
> > join? How can I accomplish this?
> >
> > Thanks,
> > Rich
>
>
From: Rich on
Yes, but in my case the test table is really the detail table and xID is the
foreign key. However, your suggestion is correct about proper relational
design. I should adopt this method.

Thank you for the suggestion.

"--CELKO--" wrote:

> If we get rid of IDENTITY and go with a proper relational design,
> would your table look like this? The constraints and a real key are
> important.
>
> CREATE TABLE Foobar
> (x_id INTEGER NOT NULL,
> x1 INTEGER NOT NULL,
> PRIMARY KEY (x_id, x1),
> stat VARCHAR(1));
>
> >> I need to select the count of the first 3 rows per each group (x_id) up to a count of 3 rows (top 3 rows - order by column x1) where the stat column is not null. if a group contains more than 3 rows where stat is not null - ignore the extra rows - only count the first 3 rows in each group <<
>
> SELKCT *
> FROM (SELECT x_id, x1,
> ROW_NUMBER() OVER (PARTITION BY x_id ORDER BY x1)
> FROM Foobar
> WHERE stat IS NOT NULL)
> AS X(x_id, x1, x_place)
> WHERE x_place <= 3;
>
>