Showing posts with label records. Show all posts
Showing posts with label records. Show all posts

Wednesday, March 21, 2012

Grabbing the Top Nth Records based on another table per group

Hi All,

I am trying to perform a SQl query that I have never attempted before.

I have a table with records such that would look like this

GroupField1 GroupField2 Field1 Amount

AAA BBB Field1Data 23.00

AAA BBB Feld2Data 24.00

AAA BBB Field3Data 8.00

BBB CCC Field1Data 25.00

BBB CCC Field2 Data 23.00

DDD BBH Field1Data 232.00

I have a second table that is like

GroupField1 GroupField2 NumberOfRows

AAA BBB 2

BBB CCC 1

DDD BBH 1

What I am trying to do is create a query that gets data from table 1 based on how many rows table 2 says to get.

I think the query would be something like

Select Top(select number of rows from table 2 where Table1.GroupField1 = Table2.GroupField1 and Table1.GroupField2 = Table2.GroupField2) from Table1

Anybody oput there have any expertise in this area?

Thank you,

Lynn

Wrong forum. Try posting on http://forums.microsoft.com/MSDN/ShowForum.aspx?ForumID=85&SiteID=1

Edward.
--
This posting is provided "AS IS" with no warranties, and confers no rights

Grab set of records per Meeting#

I have a set of records with a repeating meeting# and ID, and I'm trying to grab the top 5 Meeting#'s.

Here's an example of some records:

Meeting# ID

1234 45942

1234 69745

1234 48441

1234 44784

1234 45878

1234 78478

1234 55698

1567 95777

1567 48748

1999 87547

1999 36487

1999 58745

1999 62478

1999 02787

1999 36987

and after getting the top 5 to look like this:

Meeting# ID

1234 45942

1234 69745

1234 48441

1234 44784

1234 45878

1567 95777

1567 48748

1999 87547

1999 36487

1999 58745

1999 62478

1999 02787

I don't want to use a cursor to get back the data. I tried using a while loop, and got a little stomped.

Thanks, Iris

Iris:

Give a look to the ROW_NUMBER() function in books online; also pay attention to the OVER(), PARTITION BY and ORDER BY clauses. I will se about getting you an example. The problem here is that there seems to be no logical order to the data.

Does your data have either (1) a CLUSTERED INDEX or (2) a PRIMARY KEY? I guess the real question is what do you mean by, "Top 5 meetings"?

|||

Hi Kent,

I had an example of that from http://www.extremeexperts.com/SQL/Articles/IterateTSQLResult.aspx, and got confused. Here's what I had:

Declare @.au_id Varchar(20)

SET ROWCOUNT 0

Select au_id, au_lname, au_fname into #Temp from authors

SET ROWCOUNT 1

Select @.au_id = au_id from #Temp

While @.@.rowcount <> 0

Begin

Select * from #Temp Where au_id = @.au_id

Delete from #Temp where au_id = @.au_id

Select @.au_id = au_id from #Temp

End

Set Rowcount 0

Drop table #Temp

I tried to change it to While @.@.rowcount <= 5 but my query just kept going and going and going....lol

Thanks, Iris

|||

Ok, for example, I was trying to grab the first 5 IDs for Meeting # 1234.

Iris

|||OK; another alternative might be to use a CROSS APPLY query.|||

Never heard of it. How does it get the top 5 IDs?

Iris

|||

Here is a way of getting the top 5 IF the top 5 are ordered by ID:

Code Snippet

--
-- Notice that this is NOT the same order
-- that you showed; if you want the TOP 5
-- from an unorderd list you might want to
-- use a temp table.
--
declare @.xample table
( Meeting# integer,
ID varchar(8)
)
insert into @.xample
select 1234, '45942' union all
select 1234, '69745' union all
select 1234, '48441' union all
select 1234, '44784' union all
select 1234, '45878' union all
select 1234, '78478' union all
select 1234, '55698' union all
select 1567, '95777' union all
select 1567, '48748' union all
select 1999, '87547' union all
select 1999, '36487' union all
select 1999, '58745' union all
select 1999, '62478' union all
select 1999, '02787' union all
select 1999, '36987'
--select * from @.xample

select Meeting#,
ID
from ( select Meeting#,
ID,
row_number() over
( partition by Meeting#
order by ID
) as Seq
from @.xample
) x
where Seq <= 5
order by Meeting#

/*
Meeting# ID
-- --
1234 44784
1234 45878
1234 45942
1234 48441
1234 55698
1567 48748
1567 95777
1999 02787
1999 36487
1999 36987
1999 58745
1999 62478
*/

Here is a way of getting the top 5 IF the top 5 are truely un-ordered:

Code Snippet

--
-- Use of a temp table allows the results
-- were initially specified.
--
declare @.xample table
( Meeting# integer,
ID varchar(8)
)
insert into @.xample
select 1234, '45942' union all
select 1234, '69745' union all
select 1234, '48441' union all
select 1234, '44784' union all
select 1234, '45878' union all
select 1234, '78478' union all
select 1234, '55698' union all
select 1567, '95777' union all
select 1567, '48748' union all
select 1999, '87547' union all
select 1999, '36487' union all
select 1999, '58745' union all
select 1999, '62478' union all
select 1999, '02787' union all
select 1999, '36987'

select Meeting#,
ID,
identity(int) as Seq
into #aTemp
from @.xample

select Meeting#,
ID
from ( select Meeting#,
ID,
row_number() over
( partition by Meeting#
order by Seq
) as Seq
from #aTemp
) x
where Seq <= 5
order by Meeting#

go

drop table #aTemp
go

/*
Meeting# ID
-- --
1234 45942
1234 69745
1234 48441
1234 44784
1234 45878
1567 95777
1567 48748
1999 87547
1999 36487
1999 58745
1999 62478
1999 02787
*/

Are either of these headed in the right direction?

|||

Thanks Kent. That makes logical sense.

Iris

|||

Code Snippet

createtable #meetings (meetingnbr int, id int)

insertinto #meetings

select 1234, 45942 union

select 1234, 69745 union

select 1234, 48441 union

select 1234, 44784 union

select 1234, 45878 union

select 1234, 78478 union

select 1234, 55698 union

select 1567, 95777 union

select 1567, 48748 union

select 1999, 87547 union

select 1999, 36487 union

select 1999, 58745 union

select 1999, 62478 union

select 1999, 02787 union

select 1999, 36987

select m.*

from #meetings m

innerjoin

(

selectdistinct meetingnbr from #meetings

)as ctl

on m.meetingnbr = ctl.meetingnbr

and m.id in

(

selecttop 5 id

from #meetings m2

where m2.meetingnbr = ctl.meetingnbr

orderby id

)

|||

You need not to have a temp table with IDENTITY. I just learnt that IDENTITY won't create a sequence number as expected.

The following query is more enough.

Code Snippet

Create Table #data (

[Meeting#] int ,

[ID] int

);

Insert Into #data Values('1234','45942');

Insert Into #data Values('1234','69745');

Insert Into #data Values('1234','48441');

Insert Into #data Values('1234','44784');

Insert Into #data Values('1234','45878');

Insert Into #data Values('1234','78478');

Insert Into #data Values('1234','55698');

Insert Into #data Values('1567','95777');

Insert Into #data Values('1567','48748');

Insert Into #data Values('1999','87547');

Insert Into #data Values('1999','36487');

Insert Into #data Values('1999','58745');

Insert Into #data Values('1999','62478');

Insert Into #data Values('1999','02787');

Insert Into #data Values('1999','36987');

;With CTE

as

(

Select

*

,Row_Number() Over (Partition By [Meeting#] Order By [Meeting#]) RowId

From

#data

)

Select

[Meeting#]

,[ID]

From

CTE

Where

RowID <=5

|||

Whenever I use row_number(), I get an error... 'row_number' is not a recognized function name. Any ideas why?

select meetingid, id
from ( select meetingid, id, row_number() over
( partition by meetingid
order by Seq )
as Seq
from #ids ) x
where Seq <= 5

order by meetingid

Iris

|||

Are you using SS 200 or 2005?

If you are using SS 2005, check the compatibility level of your db, and be sure it is 90. See sp_dbcmptlevel is BOL. If you are using SS 2000, then try:

select a.*

from dbo.t1 as a

where [ID] in (

select top 5 [ID]

from dbo.t1 as b

where b.Meeting# = a.Meeting#

order by [ID] ASC

)

go

AMB

|||

I am using SS 2000.

Thanks, Iris

|||

Thanks, this part worked for SS2000.

Iris

Friday, February 24, 2012

Global temp tables in SQL Server

Hi!
I have a stored proc that creates a global temp table. How can I have multiple users select records from and insert records in that table without overwriting and/or deleting data?
Thanks so much for your help!
-ParulA global temp table is like any other table.
How would you prevent users from overwriting data in a permanent table?
A better question is why are you using a global temporary table, and would local temporary tables suffice?|||I am using a global temp table because I have the following:

Stored Proc A calls Stored Proc B calls Stored Proc C
(both Stored Proc B and C need global temp tables)

Is it possible to somehow lock these tables so the records inserted by one are not affected by another. Is there a way to use some kind of a userID?|||I am using a global temp table because I have the following:

Stored Proc A calls Stored Proc B calls Stored Proc C
(both Stored Proc B and C need global temp tables)This does note require the use of "GLOBAL" temporary tables (prefixed with "##"). It only requires "LOCAL" temporary tables (prefixed with "#").|||Won't the variables lose scope if local temp tables are used?|||Not if one procedure calls the next. Then they are nested, and any temporary table declared in the outermost procedure exists until that procedure completes, making it available to the nested procedures.|||The downside to any temp table being used by nested procs is that each and every nested proc will recompile each time it is called. This could cause severe overhead in the execution time.|||ehhhhh...I've yet to see compile time become a factor outside of processes that are run hundreds of times per hour. And you'd have the same problem with global temporary tables.|||In any case....

Add a column to your table..and this could be employed using a permanent table...that carries the spid of the transaction

Use @.@.SPID to insert the value into the column, then each sproc would use the SPID in the predicate. This in effect would isolate the data from the other sproc calls|||That should work, thanks!|||You should make a permanent table though...what for example, do you think would happen if you had a global table in existance and then tried to create it again?

Maybe you can explain to use what you are trying to do instead of trying to sledge hammer a solution with technology

Simple is usually the best answer|||while i am using a global table, if the stored proc is running in multiple sessions, it errors out saying "##temp already exists" or "it cannot be dropped."|||In any case....

Add a column to your table..and this could be employed using a permanent table...that carries the spid of the transaction

Use @.@.SPID to insert the value into the column, then each sproc would use the SPID in the predicate. This in effect would isolate the data from the other sproc calls
We gotta agree to disagree on this one. I doubt that a permanent table is an appropriate solution tohis problem, and adding the SPID to a global temporary table is just a hack for treating it like a local temporary table.|||so what else do you recommend i should try?|||Local.

Temporary.

Tables.|||Who's we?

And you mean respectfully diagree...you wouldn't want to get banned

In any case, I'd rather know what you are really trying to accomplish in the first place.

Also, it would be interesting to know how much data we are talking about.|||You lookin' fer a fight, Joisey-boy?

You are free to "diagree" with me, while'st I shall "disagree" with you (respectfully, as always).

Sunday, February 19, 2012

Giving permission to view CERTAIN records

I've been looking through permissions to see if it's possible to grant a user permission to see only certain records from a table.

For example:

I'm granting users to view records in the table 'Sales', but I only want the users to see their respective data.

User A should only be able to see Sales where Sales.Location = 1

User B should only be able to see Sales where Sales.Location = 2

... and so on.

I believe I've read this is possible, but in looking through the permissions you can define, I've only found where you can limit the columns a user sees, not records.

Anyone have any ideas or did I just remember something wrong?

This cannot be done through permissions today. This topic is known as row-level-security. You can search this forum for old threads on this topic. The following whitepaper may also be useful to you:

http://www.microsoft.com/technet/prodtechnol/sql/2005/multisec.mspx

For your example, one solution could be to use two views that filter the sales data and grant permission on each view to a different user. Users should not be able to access data directly, only through the views they have access to.

Thanks
Laurentiu

|||

Great! This sounds both useful and preferable. Too bad that when the project I'm working on gets under way, they'll likely be a couple hundred different users. Good thing I'm not developing it!

Thanks!

|||

You don't really need a view for each user, you'll need one for each type of user access you need to grant.

Also, the toolkit used by the whitepaper I mentioned is available at http://blogs.msdn.com/publicsector/archive/2006/11/16/sql-server-2005-label-security-toolkit.aspx.

Thanks
Laurentiu

|||

You might try something like this:

create table Account(AccountName sysname, Location int)

insert Account values('mydomain\myuser', 1)

create table Sales(SalesData varchar(20), Location int)

insert Sales values ('xyz', 1)

go

create view vwSales as

select Sales.* from Sales join Account on Sales.Location = Account.Location

where Account.AccountName = suser_sname()

This assumes that the user is logged into SQL Server with their Windows user account. If they are using a service account or a non-Windows account, this won't work.

Ron Rice

|||

In our Marketing Information System, end-users see only views, corresponding to their department and position.

Who needs row level security when you can create views...

Giving permission to view CERTAIN records

I've been looking through permissions to see if it's possible to grant a user permission to see only certain records from a table.

For example:

I'm granting users to view records in the table 'Sales', but I only want the users to see their respective data.

User A should only be able to see Sales where Sales.Location = 1

User B should only be able to see Sales where Sales.Location = 2

... and so on.

I believe I've read this is possible, but in looking through the permissions you can define, I've only found where you can limit the columns a user sees, not records.

Anyone have any ideas or did I just remember something wrong?

This cannot be done through permissions today. This topic is known as row-level-security. You can search this forum for old threads on this topic. The following whitepaper may also be useful to you:

http://www.microsoft.com/technet/prodtechnol/sql/2005/multisec.mspx

For your example, one solution could be to use two views that filter the sales data and grant permission on each view to a different user. Users should not be able to access data directly, only through the views they have access to.

Thanks
Laurentiu

|||

Great! This sounds both useful and preferable. Too bad that when the project I'm working on gets under way, they'll likely be a couple hundred different users. Good thing I'm not developing it!

Thanks!

|||

You don't really need a view for each user, you'll need one for each type of user access you need to grant.

Also, the toolkit used by the whitepaper I mentioned is available at http://blogs.msdn.com/publicsector/archive/2006/11/16/sql-server-2005-label-security-toolkit.aspx.

Thanks
Laurentiu

|||

You might try something like this:

create table Account(AccountName sysname, Location int)

insert Account values('mydomain\myuser', 1)

create table Sales(SalesData varchar(20), Location int)

insert Sales values ('xyz', 1)

go

create view vwSales as

select Sales.* from Sales join Account on Sales.Location = Account.Location

where Account.AccountName = suser_sname()

This assumes that the user is logged into SQL Server with their Windows user account. If they are using a service account or a non-Windows account, this won't work.

Ron Rice

|||

In our Marketing Information System, end-users see only views, corresponding to their department and position.

Who needs row level security when you can create views...