Showing posts with label column. Show all posts
Showing posts with label column. Show all posts

Thursday, March 29, 2012

Granting UPDATE for only certain columns in a table

I have tried using the SQL statement shown below to grant UPDATE permissions for a single column in a single table to a user with db_datareader privileges.

grant update (col_1) on trs.dbo.table_1 to calc

When I then run a SQL script that has an UPDATE for col_1 on trs.dbo.table_1, I get an error message

Msg 230, Level 14, State 1, Line 2100

UPDATE permission denied on column 'col_2' of object 'table_1', database 'TRS', schema 'dbo'.

Why is the error message referring to "col_2" when my SQL statement is trying to update "col_1"?

When I performed the "grant" I did it with an account that has db_owner, db_securityadmin, and db_ddladmin privileges.

This worked in SQL Server 2000. What must I do to get it to work in SQL Server 2005?

Sorry Dan - can you show us the update query?|||

You are going to have to dig deeper. The only scenario that I can think of where an update to another column causes an update to another column causing issues like this is with a trigger with dynamic SQL (a real no-no in almost all cases, but it could exist). The fact that you have appended database names to the ddl makes me curious as to how that *might* cause issue, but I don't even see how anything cross-database could be an issue either.

Here is a script that shows what I am meaning:

create table test
(
column1 int,
column2 int
)
go
create user fred without login
go
execute as user = 'fred'
go
update test
set column1 = 1
/*
Msg 229, Level 14, State 5, Line 1
The UPDATE permission was denied on the object 'test', database 'tempdb', schema 'dbo'.
*/
go
revert
go
grant update (column1) on test to fred
go
execute as user = 'fred'
go
update test
set column1 = 1
/*
(0 row(s) affected)
*/
update test
set column2 = 1
/*
Msg 230, Level 14, State 1, Line 1
The UPDATE permission was denied on the column 'column2' of the object 'test', database 'tempdb', schema 'dbo'.
*/
go
revert
go
create trigger test$updateColumn1
on test
after update
as
begin
exec('
update test
set column2 = 2')
end
go
execute as user = 'fred'
go
update test
set column1 = 1
/*
Msg 230, Level 14, State 1, Line 2
The UPDATE permission was denied on the column 'column2' of the object 'test', database 'tempdb', schema 'dbo'.
*/

If you could post a full example like this showing your issue I think that you might find your error, or certainly one of us can help you out.

|||

Thanks for your support.

Here is a small bit of code that is able to produce the problem. It seems to be associated with having a JOIN in the UPDATE statement. An UPDATE without the JOIN works just fine.

Using a DB_OWNER account perform the following table creation, insert, and grant commands:

create table trs.dbo.people
(
name varchar(10),
sex varchar(10),
age smallint
)

insert into people values ('tom', 'male', 10)
insert into people values ('jane', 'female', 18)
insert into people values ('sue', 'female', 22)

create table trs.dbo.grads
(
name varchar(10),
grad_yr varchar(4)
)

insert into grads values ('jane', '2006')
insert into grads values ('sue', '2002')

grant update (age) on trs.dbo.people to calc

Then, from the db_datareader account, calc, run the following UPDATE statements, one at a time.

update p
set age = 40
from trs.dbo.people p
where (age is not null)
;

update p
set age = 35
from trs.dbo.people p
inner join trs.dbo.grads g
on p.name = g.name
where (age is not null)
;

The first one works. The second one fails with error message

Msg 230, Level 14, State 1, Line 1

UPDATE permission denied on column 'name' of object 'people', database 'TRS', schema 'dbo'.

Does this help?

|||Very nice. I have no answer as to why this is, but I will check around and let you know.|||Thanks!|||Do you have select permission on the other columns?

I know it's complaining that you don't have UPDATE permission... but it's complaining about your access to another column that's involved in the join.

Rob|||

Rob,

If I enter SELECT statements against the two tables, while connected as "CALC", all the rows from each table are returned.

select * from grads;

select * from people;

I have also tried using the DB_OWNER connection to explicity GRANT SELECT access to those tables, and still get the same error message when I try to update the AGE column, as in the example above, while connected as "CALC".

grant select on trs.dbo.people to calc
grant select (name) on trs.dbo.people to calc
grant select on trs.dbo.grads to calc

Dan

|||Ok, so that idea wasn't right. ;)

It's somehow related to the fact that you're joining the table you're updating to another table, and the engine thinks that it needs to be able to update that column too. It doesn't of course, but the fact that the column is used in the query must be confusing it somehow.

I assume this works just fine if you grant update access to the name column too?

One workaround might be to wrap it up in a table expression, but if that works, it'll just be down to luck.

Rob|||

The same code runs just fine with SQL Server 2000. I only ran into a problem when I tried moving it over to SQL Server 2005.

If I grant UPDATE access on the NAME column, as identified in the Error message, then the code runs.

But I hate to do that, since CALC is supposed to be a relatively "unprivileged" user, with db_datareader general privileges only, and CREATE TABLE privileges -- and in my actual application, these other columns are the PRIMARY KEY columns in the tables.

Adding a new column to the table, a column to which CALC has UPDATE permission, was a way of avoiding creating an entirely new table for CALC to own, with 500,000 rows, and a 20-byte primary key that incorporates 5 columns. Had I created such a new table my processing queries would have to JOIN this table to the 500,000 row counterpart. Instead of such a JOIN I added a new column as a simpler, faster solution.

Dan

|||Hmm... I'll have to do some more hunting. I'd like to say "try using a cte or view", or something like that (based on the fact that you might be able to update a view without it thinking it needs to be able to update the joining column), but I actually don't know if that will help. I'll have to recreate the situation locally and try some things.

But hopefully some of the other guys will already know the answer to this.

Rob|||

This seems like such a "natural" thing to have to do, in most any application that requires user permissions to only certain columns in a table.

Consider a table that connects salary to social security number. If you want to allow someone to edit SALARY, must you also allow them to edit SOCIAL SECURITY NUMBER?

What if you are running a medical office and have some sort of PATIENT NUMBER in the medical records. If you want to edit information on their account, such as their ZIP CODE, must you also allow them to edit the PATIENT NUMBER?

Is there maybe a greater need in SQL Server 2005 to create a new ROLE for every different set of permissions that one might need in the database, rather than use GRANT UPDATE to customize access to different users?

I'm not now at my office where I could try it, but I'm wondering if some SYSTEM table stores UPDATE permissions, and if a user has NOT received GRANT or DENY UPDATE permissions on a column in a table, maybe an INNER JOIN is being used, rather than an OUTER JOIN on the permissions table. If that is true, I suppose I can DENY UPDATE on the NAME column in the example, and the query should work, because it finds an entry in the permissions table for the NAME column, even though that entry is "DENY." So tomorrow at the office I'll try DENY UPDATE (name) on TRS.DBO.PEOPLE to CALC. (I'll have to check the syntax on the DENY statement. I think I noticed one in the past few days.)

Dan

|||

This is almost clearly a bug that I posted here: https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=257897

A (not terribly satisfying) workaround is to move the join to a subquery:

update p set age = 35
from trs.dbo.people p
where p.name in (select p2.name
from trs.dbo.people p2
inner join trs.dbo.grads g
on p.name = g.name
where (age is not null))

Here is the simple repro with users I posted:

create database trs
go
use trs
go
create table trs.dbo.people
(
name varchar(10),
sex varchar(10),
age smallint
)

insert into people values ('tom', 'male', 10)
insert into people values ('jane', 'female', 18)
insert into people values ('sue', 'female', 22)

create table trs.dbo.grads
(
name varchar(10),
grad_yr varchar(4)
)

insert into grads values ('jane', '2006')
insert into grads values ('sue', '2002')
go
create user calc without login
sp_addrolemember 'db_datareader','calc'
go
grant update (age) on trs.dbo.people to calc
go

--Then, from the db_datareader account, calc, run the following UPDATE
statements, one at a time.
execute as user = 'calc'
go

update p
set age = 40
from trs.dbo.people p
where (age is not null)
;

update p
set age = 35
from trs.dbo.people p
inner join trs.dbo.grads g
on p.name = g.name
where (age is not null)
;

/*
Msg 230, Level 14, State 1, Line 1
The UPDATE permission was denied on the column 'name' of the object
'people', database 'trs', schema 'dbo'.
*/
--

|||

Louis,

Thanks for posting that to the MS "feedback" site.

I tried my "DENY UPDATE" idea, but it didn't fix anything: the same error message was obtained for the same UPDATE statement.

There aren't many places in my code where I am performing updates on columns where the GRANT UPDATE permission is limited to certain columns -- maybe a few dozen. I'll just make the code edits corresponding to your suggestion, and maybe un-do them if/when a patch occurs.

Thanks again.

Dan

|||

Louis,

I reworked my code for SQL Server 2005, using the technique you suggested (or something quite similar):

update p set age = 35
from trs.dbo.people p
where p.name in (select p2.name
from trs.dbo.people p2
inner join trs.dbo.grads g
on p.name = g.name
where (age is not null))

In all but a single instance, this solution worked just fine.

In the remaining instance, the value that I need for the SET clause is from the JOINed table. Were we using the example I supplied (rather than my actual code), this could appear as

update p
set age = cast(g.grad_yr as int) + 18 - 2006
from trs.dbo.people p
inner join trs.dbo.grads g
on p.name = g.name
where (age is not null)

I didn't see any easy way around this, other than to create a CURSOR on "select distinct GRAD_YR from GRADS" and using a LOOP over the CURSOR values, and having code like

update p
set age = @.grad_yr + 18 - 2006
from trs.dbo.people p
where (age is not null) and p.name in (select distinct name from trs.dbo.grads where grad_yr = @.grad_yr)

I am thankful that the number of values for my CURSOR is less than 10, in my actual application.

If you can think of a better alternative, I would be happy to learn of it.

Thanks.

Dan

Friday, March 23, 2012

Grant and Revoke on a column

I am trying to give limited privileges to a login account on a table, but it
doesn't seem to work. I have a link table in Access 97 and my SQL server is
version 7. Some columns are supposed to be read only and some columns are
supposed to be read-only.
I use the script below
revoke all privileges on stores to shipdirect1
grant update on stores(creditlimit) to shipdirect1
What am I doing wrong?Arne,
SQL Server does not support column level permissions. Even if it did it is
doubtful Access supports it. You will be better off setting up a view with
the permitted columns and granting permissions to it to the user.
Ilya
"Arne" <Arne@.discussions.microsoft.com> wrote in message
news:CC4D4275-A5EC-4C30-B875-8A5CB2626C65@.microsoft.com...
> I am trying to give limited privileges to a login account on a table, but
it
> doesn't seem to work. I have a link table in Access 97 and my SQL server
is
> version 7. Some columns are supposed to be read only and some columns are
> supposed to be read-only.
> I use the script below
> revoke all privileges on stores to shipdirect1
> grant update on stores(creditlimit) to shipdirect1
> What am I doing wrong?
>|||SQL Server 7.0 that is.
"Ilya Margolin" <ilya_no_spam_@.unapen.com> wrote in message
news:OdYOh6GFFHA.2756@.TK2MSFTNGP15.phx.gbl...
> Arne,
> SQL Server does not support column level permissions. Even if it did it is
> doubtful Access supports it. You will be better off setting up a view with
> the permitted columns and granting permissions to it to the user.
> Ilya
> "Arne" <Arne@.discussions.microsoft.com> wrote in message
> news:CC4D4275-A5EC-4C30-B875-8A5CB2626C65@.microsoft.com...
but
> it
> is
are
>|||Actually, SQL Server DOES support column-level permissions and has done so
since the earliest version.
The problem is probably related to linking to the Access table, if access
doesn't support this.
How do you know it doesn't work? Are you getting an error? What does it say?
HTH
--
Kalen Delaney
SQL Server MVP
www.SolidQualityLearning.com
"Ilya Margolin" <ilya_no_spam_@.unapen.com> wrote in message
news:OdYOh6GFFHA.2756@.TK2MSFTNGP15.phx.gbl...
> Arne,
> SQL Server does not support column level permissions. Even if it did it is
> doubtful Access supports it. You will be better off setting up a view with
> the permitted columns and granting permissions to it to the user.
> Ilya
> "Arne" <Arne@.discussions.microsoft.com> wrote in message
> news:CC4D4275-A5EC-4C30-B875-8A5CB2626C65@.microsoft.com...
> it
> is
>|||Kalen,
When I update a column that is supposed to be read-only I don't the
exception that I expected.
However I found some MS Access properties that solved the problem for me.
Arne.
"Kalen Delaney" wrote:

> Actually, SQL Server DOES support column-level permissions and has done so
> since the earliest version.
> The problem is probably related to linking to the Access table, if access
> doesn't support this.
> How do you know it doesn't work? Are you getting an error? What does it sa
y?
> --
> HTH
> --
> Kalen Delaney
> SQL Server MVP
> www.SolidQualityLearning.com
>
> "Ilya Margolin" <ilya_no_spam_@.unapen.com> wrote in message
> news:OdYOh6GFFHA.2756@.TK2MSFTNGP15.phx.gbl...
>
>

Wednesday, March 21, 2012

Grand Total

I am having a hard time figuring out how to total a column. If I have
January Febuary March
Type1 10 4 3
Type2 4 8 2
Type3 1 9 1
I want a total for each month, NOT each type. I have tried right
clicking on Type and choosing subtotal but that only gives me 10, if I
try to change the expression to a Sum, I get an error that aggregates
can't live in groups.
I have read that I should add a textbox and enter an expression. I
have tried that too and got closer but it seems the only scope that is
actually allowed (dispite what BOL says) is the dataset, which does
give me the total for the whole matix, but I only want each column
totaled. I have tried to replace DataSet1 in the expression with the
name of the Month group, but that errors too.
Am I just blind, this shouldn't be this difficult, right?I have a similar problem but in my case I can't add the columns. My
idea ould be to adjust the MDX statement to get the total row. Just add
the root element to the columns of your query and you should get the
total line.
root element example: [Organisation].[Business Area
Code].CurrentMember.Parent
pjcwik@.gmail.com schrieb:
> I am having a hard time figuring out how to total a column. If I have
> January Febuary March
> Type1 10 4 3
> Type2 4 8 2
> Type3 1 9 1
> I want a total for each month, NOT each type. I have tried right
> clicking on Type and choosing subtotal but that only gives me 10, if I
> try to change the expression to a Sum, I get an error that aggregates
> can't live in groups.
> I have read that I should add a textbox and enter an expression. I
> have tried that too and got closer but it seems the only scope that is
> actually allowed (dispite what BOL says) is the dataset, which does
> give me the total for the whole matix, but I only want each column
> totaled. I have tried to replace DataSet1 in the expression with the
> name of the Month group, but that errors too.
> Am I just blind, this shouldn't be this difficult, right?|||What kind of control are you using - Table or Matrix?
"pjcwik@.gmail.com" wrote:
> I am having a hard time figuring out how to total a column. If I have
> January Febuary March
> Type1 10 4 3
> Type2 4 8 2
> Type3 1 9 1
> I want a total for each month, NOT each type. I have tried right
> clicking on Type and choosing subtotal but that only gives me 10, if I
> try to change the expression to a Sum, I get an error that aggregates
> can't live in groups.
> I have read that I should add a textbox and enter an expression. I
> have tried that too and got closer but it seems the only scope that is
> actually allowed (dispite what BOL says) is the dataset, which does
> give me the total for the whole matix, but I only want each column
> totaled. I have tried to replace DataSet1 in the expression with the
> name of the Month group, but that errors too.
> Am I just blind, this shouldn't be this difficult, right?
>|||OK I got it figured out.
When looking at the matrix report the field names were in the field
spots, but... What needed to happen was to make the field names a SUM.
So instead of just =(Fields!allitmonthclosedcalls.Value) what was
needed was =Sum(Fields!allitmonthclosedcalls.Value) Then the SubTotal
feature worked. The SubTotal can be seen when you right click on the
row group header and choose SubTotal. (I hate it when specifics aren't
given)
Without the SUM in front of the field I only got 10 in the SubTotal
field, but with the =Sum(Fields!allitmonthclosedcalls.Value) then it
added the whole column.
I am assuming that the way it is being read is that the Sum of 10 is
10, the Sum of 4 is 4 and the Sum of 1 is 1. Then the SubTotal is the
Sum of the Sums. A screwy way to get where I needed to be, but it
works.
Hope this helps.
--Pete
pjcwik@.gmail.com wrote:
> I am having a hard time figuring out how to total a column. If I have
> January Febuary March
> Type1 10 4 3
> Type2 4 8 2
> Type3 1 9 1
> I want a total for each month, NOT each type. I have tried right
> clicking on Type and choosing subtotal but that only gives me 10, if I
> try to change the expression to a Sum, I get an error that aggregates
> can't live in groups.
> I have read that I should add a textbox and enter an expression. I
> have tried that too and got closer but it seems the only scope that is
> actually allowed (dispite what BOL says) is the dataset, which does
> give me the total for the whole matix, but I only want each column
> totaled. I have tried to replace DataSet1 in the expression with the
> name of the Month group, but that errors too.
> Am I just blind, this shouldn't be this difficult, right?

Monday, March 12, 2012

Good SQL Query

Folks, i've got a table with a column; ACCOUNT VARCHAR(30). All the values numeric though. (leave abt the datatype yet).
The column is clustered indexed.

SELECT * FROM MYTABLE WHERE LEFT(ACCOUNT,3)='123'
execution plan shows CLUSTERED INDEX SCAN.

SELECT * FROM MYTABLE WHERE ACCOUNT LIKE '123%'
execution plan shows CLUSTERED INDEX SEEK.

How, why. Why doesn't the optimizer works good for the first query?

Howdy!Can you refraze the question. Can it be built with the query anylzer?|||LEFT is seen by the optimizer as similar to UPPER. In short, the query plan looks at the function result as an unknown value, and thus the table scan.|||LEFT is seen by the optimizer as similar to UPPER. In short, the query plan looks at the function result as an unknown value, and thus the table scan.well, that's pretty stupid of it, eh :)

oh, i don't mean in the general sense, i am forever telling people not to do stuff like

... where year(transdate) = year(getdate())

i mean specifically in the case of the LEFT function|||Can you refraze the question. Can it be built with the query anylzer?

create table mytable (account varchar(10))

go
create clustered index myindex on mytable(account)
go
declare @.v int
set @.v=1
while @.v<9000
begin
insert mytable select 'abcdefgh'
set @.v=@.v+1
end

-- table scan
select * from mytable where left(account,3)='abc'

-- index seek
select * from mytable where account like 'abc%'

drop table mytable|||is there an index on that column at all ?|||It's likely that the scan occurs because left has to retrieve the whole thing while the like only retrieves the first three characters. The clustered index is going to organize that column by varchar physically on the disk, so the like statement will retrieve two indexes and everything in between, versus the left which will have to check every record "in between".

Does that make sense ?

Cheers,
-Kilka|||It's NonSargable

http://www.sql-server-performance.com/sql_server_performance_audit8.asp

Good Query Writing......

SQL Query,
Col1 in Table1 has the following data.
Col1
1
2
2
3
4
IS it possible to run a query where I can the Col2 as sum from previous
column for each row in col1?
Col1
Col2
1
1
2
3
2
5
3
8
4
12
Thanks,
Hiltondepends what you mean by previous column.
1, 2, 2,
Which 2 comes first? To define that you will need some other value to sort on
If neither is before the other then
select i, sum((select t2.i from tbl where t2.i <= t.i)) from tbl
If there's no other column to sort then use a temp table with an identity
select i, id = identity(int,1,1) as id into #a from tbl
select i, sum((select t2.i from #a where t2.i < t.i or (t2.i = t.i and t2.id
<= t.id)))
from #a
"John Hilton" wrote:
> SQL Query,
>
> Col1 in Table1 has the following data.
>
> Col1
> 1
> 2
> 2
> 3
> 4
>
>
> IS it possible to run a query where I can the Col2 as sum from previous
> column for each row in col1?
>
> Col1
> Col2
> 1
> 1
> 2
> 3
> 2
> 5
> 3
> 8
> 4
> 12
>
>
> Thanks,
> Hilton
>
>|||Nigel Rivett, I really appricate your time in replying this post!!!
Since the formatting is lost in the post,
I am posting this again.
Col1 in Table1 has the following data.
Col1
1
2
2
3
4
Is it possible to run a query where I can get the Col2 as sum from previous
column for each row in col1?
So the query result should be as follows.
Col2
1
3
5
8
12
Thanks,
Hilton|||Here's an alternative to Nigel's:
SELECT [ID] = IDENTITY(INT, 1, 1)
,Col1
INTO #Temp
FROM tbl
ORDER BY Col1 ASC
SELECT Col1 = AVG(t1.Col1)
Col2 = SUM(t2.Col1)
FROM #Temp AS t1
INNER JOIN
#Temp AS t2
ON t1.[ID] >= t2.[ID]
GROUP BY t1.[ID]
ORDER BY t1.[ID]
DROP #Temp
Sincerely,
Anthony Thomas
"John Hilton" <John_Hilton2004@.hotmail.com> wrote in message
news:%23Fw2HOx4EHA.1188@.tk2msftngp13.phx.gbl...
Nigel Rivett, I really appricate your time in replying this post!!!
Since the formatting is lost in the post,
I am posting this again.
Col1 in Table1 has the following data.
Col1
1
2
2
3
4
Is it possible to run a query where I can get the Col2 as sum from previous
column for each row in col1?
So the query result should be as follows.
Col2
1
3
5
8
12
Thanks,
Hilton

good practice?

A couple of questions.
1)
I have a column Event_End_Date with smalldatetime data type. I also have
following update scripts that gets executed every day. Basically I do not
care about the time portion of smalldatetime (or rather it needs to be
default time format 00:00:00)
UPDATE tblEvents
SET Event_End_Date = CONVERT(VARCHAR, GETDATE(), 101)
Now is it more proper to program it following way? I know in other
programming language like Java, C++, you would always have to explicitly
cast it to the appropriate data type. How sensitive do I need to be when it
comes to casting in TSQL?
UPDATE tblEvents
SET Event_End_Date = CAST(CONVERT(VARCHAR, GETDATE(), 101) AS SMALLDATETIME)
2) I have read somewhere that the following query needs to be rewritten
SELECT *
FROM tblEvents
WHERE Event_End_Date = '6/7/2006'
to
SELECT *
FROM tblEvents
WHERE DATEPART(YEAR, Event_End_Date) = 2006 AND DATEPART(MONTH,
Event_End_Date) = 6 AND DATEPART(Day, Event_End_Date) = 7
Of course, should there be an index Event_End_Date, it is useless with the
above query. What's your opinion on this matter relating to datetime data
types?
Thanks all.Justin,
If you use style 112, you do not have to worry about casting because sql
server will always interprets the value correctly as a datetime value, not
matter what language or date format is using your server.
UPDATE tblEvents
SET Event_End_Date = CONVERT(varchar(8), GETDATE(), 112)
If you do not pass the time portion from the client application, sql server
will default it to 00:00:00.000

> 2) I have read somewhere that the following query needs to be rewritten
> SELECT *
> FROM tblEvents
> WHERE Event_End_Date = '6/7/2006'
> to
> SELECT *
> FROM tblEvents
> WHERE DATEPART(YEAR, Event_End_Date) = 2006 AND DATEPART(MONTH,
> Event_End_Date) = 6 AND DATEPART(Day, Event_End_Date) = 7
Not really. If the values in the column has time portion equal to
"00:00:00.000", then it will work without problems. If the values in the
column include tiem portion other that 12 AM, then you should use the patter
n:
...
where
Event_End_Date >= convert(varchar(8), @.d, 112)
Event_End_Date < dateadd(day, 1, convert(varchar(8), @.d, 112))
This way, sql server will make a proper use of an index if this exists. When
you manipulate the column in the "where" clause, sql server does not conside
r
the expresion as a search argument.
Example:
..
where
Event_End_Date >= '20060607'
Event_End_Date < '20060608'
The ultimate guide to the datetime datatypes
http://www.karaszi.com/SQLServer/info_datetime.asp
Should I use BETWEEN in my database queries?
http://www.aspfaq.com/show.asp?id=2280
AMB
"Justin" wrote:

> A couple of questions.
> 1)
> I have a column Event_End_Date with smalldatetime data type. I also have
> following update scripts that gets executed every day. Basically I do not
> care about the time portion of smalldatetime (or rather it needs to be
> default time format 00:00:00)
> UPDATE tblEvents
> SET Event_End_Date = CONVERT(VARCHAR, GETDATE(), 101)
> Now is it more proper to program it following way? I know in other
> programming language like Java, C++, you would always have to explicitly
> cast it to the appropriate data type. How sensitive do I need to be when
it
> comes to casting in TSQL?
> UPDATE tblEvents
> SET Event_End_Date = CAST(CONVERT(VARCHAR, GETDATE(), 101) AS SMALLDATETIM
E)
> 2) I have read somewhere that the following query needs to be rewritten
> SELECT *
> FROM tblEvents
> WHERE Event_End_Date = '6/7/2006'
> to
> SELECT *
> FROM tblEvents
> WHERE DATEPART(YEAR, Event_End_Date) = 2006 AND DATEPART(MONTH,
> Event_End_Date) = 6 AND DATEPART(Day, Event_End_Date) = 7
> Of course, should there be an index Event_End_Date, it is useless with the
> above query. What's your opinion on this matter relating to datetime data
> types?
> Thanks all.
>
>

Friday, March 9, 2012

Good or Bad practice?

Is it a bad practice to create small, one column tables to store list type
data?
like,
nameprefix: Mr., Mrs., Miss, Dr., Sir
name suffix: Jr., Sr, Esq., Md., Phd., I, II, II....
My thought is if you ever want to add to these lists you only have to do it
in the table instead of any application that uses the fields, on the other
hand the fields rarely change and you would always have to query the
database to get the values.
I know its trivial, but does anyone have an opinion on this?DAC,
Check out
http://www.windowsitpro.com/SQLServ.../5226/5226.html
HTH
Jerry
"DazedAndConfused" <AceMagoo61@.yahoo.com> wrote in message
news:uHGUg0guFHA.2008@.TK2MSFTNGP10.phx.gbl...
> Is it a bad practice to create small, one column tables to store list type
> data?
> like,
> nameprefix: Mr., Mrs., Miss, Dr., Sir
> name suffix: Jr., Sr, Esq., Md., Phd., I, II, II....
> My thought is if you ever want to add to these lists you only have to do
> it in the table instead of any application that uses the fields, on the
> other hand the fields rarely change and you would always have to query the
> database to get the values.
> I know its trivial, but does anyone have an opinion on this?
>
>|||I personally make them two column tables, with an IDENTITY column, because
if you ever have to globalize your app, you will need different information
for each supported language, so it's simpler to store the IDENTITY value in
the tables that use information in the list instead of the localized values.
"DazedAndConfused" <AceMagoo61@.yahoo.com> wrote in message
news:uHGUg0guFHA.2008@.TK2MSFTNGP10.phx.gbl...
> Is it a bad practice to create small, one column tables to store list type
> data?
> like,
> nameprefix: Mr., Mrs., Miss, Dr., Sir
> name suffix: Jr., Sr, Esq., Md., Phd., I, II, II....
> My thought is if you ever want to add to these lists you only have to do
it
> in the table instead of any application that uses the fields, on the other
> hand the fields rarely change and you would always have to query the
> database to get the values.
> I know its trivial, but does anyone have an opinion on this?
>
>|||Basically what you're talking about here is creating a domain - the set
of allowed values for a column.
To create a domain, my preferred way is to create a table and reference
that table.
This can be done with a check constraint as well, but if the allowed
values change you would have to alter the table.
I would never hard-code these into an application - too easy to get out
of synch with the domain.
DazedAndConfused wrote:

>Is it a bad practice to create small, one column tables to store list type
>data?
>like,
>nameprefix: Mr., Mrs., Miss, Dr., Sir
>name suffix: Jr., Sr, Esq., Md., Phd., I, II, II....
>My thought is if you ever want to add to these lists you only have to do it
>in the table instead of any application that uses the fields, on the other
>hand the fields rarely change and you would always have to query the
>database to get the values.
>I know its trivial, but does anyone have an opinion on this?
>
>
>|||"DazedAndConfused" <AceMagoo61@.yahoo.com> wrote in message
news:uHGUg0guFHA.2008@.TK2MSFTNGP10.phx.gbl...
> Is it a bad practice to create small, one column tables to store list type
> data?
> like,
> nameprefix: Mr., Mrs., Miss, Dr., Sir
> name suffix: Jr., Sr, Esq., Md., Phd., I, II, II....
> My thought is if you ever want to add to these lists you only have to do
> it in the table instead of any application that uses the fields, on the
> other hand the fields rarely change and you would always have to query the
> database to get the values.
> I know its trivial, but does anyone have an opinion on this?
>
To summarize the other (on point) comments: Good practice.
David|||Agreed. Good practice.
"Brian Selzer" <brian@.selzer-software.com> wrote in message
news:uUxrf6guFHA.3756@.tk2msftngp13.phx.gbl...
> I personally make them two column tables, with an IDENTITY column, because
> if you ever have to globalize your app, you will need different
information
> for each supported language, so it's simpler to store the IDENTITY value
in
> the tables that use information in the list instead of the localized
values.
> "DazedAndConfused" <AceMagoo61@.yahoo.com> wrote in message
> news:uHGUg0guFHA.2008@.TK2MSFTNGP10.phx.gbl...
type
> it
other
>|||By storing the meta data in a table, you make it easily accessable and
define what the valid options are. If you let the app developers store this
info in arrays, I swear it will be scattered in 10 different locations at
least. Also, even though you may think that the table needs only the one
column, you will probably find that other attributes can be logically stored
there as well.
"DazedAndConfused" <AceMagoo61@.yahoo.com> wrote in message
news:uHGUg0guFHA.2008@.TK2MSFTNGP10.phx.gbl...
> Is it a bad practice to create small, one column tables to store list type
> data?
> like,
> nameprefix: Mr., Mrs., Miss, Dr., Sir
> name suffix: Jr., Sr, Esq., Md., Phd., I, II, II....
> My thought is if you ever want to add to these lists you only have to do
> it in the table instead of any application that uses the fields, on the
> other hand the fields rarely change and you would always have to query the
> database to get the values.
> I know its trivial, but does anyone have an opinion on this?
>
>|||You have two choices:
1) a one-column table
2) a CHECK() constraint
Rule of thumb: If the list is long and changes a lot and the data
element is used in many places, use #1. If the list is short, fixed and
the data element is used in one place, use #2
Get a copy of SQL PROGRAMMING STYLE for the answers to these and other
questions.|||DazedAndConfused wrote:
> Is it a bad practice to create small, one column tables to store list
> type data?
> like,
> nameprefix: Mr., Mrs., Miss, Dr., Sir
> name suffix: Jr., Sr, Esq., Md., Phd., I, II, II....
> My thought is if you ever want to add to these lists you only have to
> do it in the table instead of any application that uses the fields,
> on the other hand the fields rarely change and you would always have
> to query the database to get the values.
> I know its trivial, but does anyone have an opinion on this?
Are you using these values to provide either validation or dropdown lists
for client-side data entry? If so, then you can't use a constraint.
I don't know what programming language you are using but it should be
possible to cache the data from these tables locally, eliminating the
necessity to go to the database every time. ASP.Net makes this easy. It can
also be done in ASP. If you are creating desktop apps, then it's even
easier.
Bob Barrows
--
Microsoft MVP -- ASP/ASP.NET
Please reply to the newsgroup. The email account listed in my From
header is my spam trap, so I don't check it very often. You will get a
quicker response by posting to the newsgroup.

Sunday, February 19, 2012

Giving Value for Identity column while inserting

I have a table with an Identity column. The latest Identity value is 1298. A row with Identity 324 was deleted by mistake and I need to insert it now. But if I insert it now it will have Identity value of 1299. I tried giving the value 324 for the Identity column in the Insert statement but it throws error. How can I insert this row with the same Identity value as before??

Quote:

Originally Posted by sajithamol

I have a table with an Identity column. The latest Identity value is 1298. A row with Identity 324 was deleted by mistake and I need to insert it now. But if I insert it now it will have Identity value of 1299. I tried giving the value 324 for the Identity column in the Insert statement but it throws error. How can I insert this row with the same Identity value as before??


Are you not able to insert using a plain insert statement on query analyser?|||You can do this by
SET IDENTITY_INSERT [table_name] ON
and then turn it off

Giving a total on a column value change

I have the following data in a table
date StartTm ElapseTm shift Job# Op#
WorkCtr Qty1 Qty2
20051218 0030 0030 13 165990 225 9 .0000 0
20051218 0100 0030 13 165990 223 9 .0000 0
20051218 0130 0145 13 165990 200 9
26219.0000 28220
20051218 0315 0030 13 165990 300 9 .0000 0
20051218 0345 0115 13 165988 100 9 .0000 0
20051218 0500 0030 13 165900 300 9 .0000 0
20051218 0530 0130 13 165975 100 9 .0000 0
20051218 2300 0100 13 166436 300 9 .0000 0
20051218 2400 0030 13 165990 100 9 .0000 0
I need to know how to calculate the quantities based on totals of
successive jobs.
For example the first total for job 165990 would be 26219
the next total for job 165990 would be 0 for Qty1
the first total for job 165988 would be 0 for Qty1
so aggregated I would want to see
165988 0
165990 26219
165990 0
I need to be able to apply a identifier to these groups of successive
jobs by date and by WorkCtr.
I group the values by work_ctr, day, start_tm, job_no
Within that grouping when the job changes give a total.
I hope I am being clear. Thanks for your time in advance.I'm .
Why is the row with 26219 the first total for job 165990? It seems that
based on start time this row is the 3rd of 4 for this job. What is the
criteria you want to use for ordering the rows for a specific job.
When you say aggregated what do you mean? Do you just mean ordered? Or are
you intending to combine the rows somehow.
Also, I am by your last set of statements. what do you mean by
apply an identifier to the groups. And what does it mean when you say when
the job changes give a total?
If you can give the full version of your desired output based on the data
that you provide and answer by above confusion it will make it easier for us
.
Thanks
Ryan Powers
Clarity Consulting
http://www.claritycon.com
"g3000" wrote:

> I have the following data in a table
> date StartTm ElapseTm shift Job# Op#
> WorkCtr Qty1 Qty2
> 20051218 0030 0030 13 165990 225 9 .0000 0
> 20051218 0100 0030 13 165990 223 9 .0000 0
> 20051218 0130 0145 13 165990 200 9
> 26219.0000 28220
> 20051218 0315 0030 13 165990 300 9 .0000 0
> 20051218 0345 0115 13 165988 100 9 .0000 0
> 20051218 0500 0030 13 165900 300 9 .0000 0
> 20051218 0530 0130 13 165975 100 9 .0000 0
> 20051218 2300 0100 13 166436 300 9 .0000 0
> 20051218 2400 0030 13 165990 100 9 .0000 0
> I need to know how to calculate the quantities based on totals of
> successive jobs.
> For example the first total for job 165990 would be 26219
> the next total for job 165990 would be 0 for Qty1
> the first total for job 165988 would be 0 for Qty1
> so aggregated I would want to see
> 165988 0
> 165990 26219
> 165990 0
> I need to be able to apply a identifier to these groups of successive
> jobs by date and by WorkCtr.
> I group the values by work_ctr, day, start_tm, job_no
> Within that grouping when the job changes give a total.
> I hope I am being clear. Thanks for your time in advance.
>|||Sorry, I actually solved the problem my issue was this
Date Job# Qty
20051201 165203 20
-- break here and total is 20 unique id
20051201 165202 15
-- break here and total is 20 unique
id
20051201 165203 10
20051201 165203 10
20051201 165203 10
20051202 165203 10
-- break here and total is
40. The above four records shoud have a unique group id
20051202 165222 05
blah blah blah
bottom line I have jobs that run and stop then start again
if the same job is started, stopped and restarted in succession that is
a unique group
if the next job is not the same as the first i needed a new unique
identifier and a total
I wanted to get totals for these groups but had no way to group those
by
just did a cursor to a table and looped through and had new colun in my
table
clear as mud?|||It's actually quite simple to solve if you don't let
the complexities of sql cloud the issue.Every block
gets an ascending unique integer.Then you can group
by this new integer.The convoluted sql comes in when
trying to derive a new integer for a new block.It's a rank
problem at most.
Ranking was implemented years ago in the RAC utility:)
Perhaps someone can wrap their head around sql 2005
ranking functions and solve it,if not I can post RAC solution:)
Check out RAC @.
www.rac4sql.net|||On 12 Jan 2006 12:40:25 -0800, g3000 wrote:

>Sorry, I actually solved the problem my issue was this
>Date Job# Qty
>20051201 165203 20
> -- break here and total is 20 unique id
>20051201 165202 15
> -- break here and total is 20 unique
>id
>20051201 165203 10
>20051201 165203 10
>20051201 165203 10
>20051202 165203 10
> -- break here and total is
>40. The above four records shoud have a unique group id
>20051202 165222 05
> blah blah blah
>bottom line I have jobs that run and stop then start again
>if the same job is started, stopped and restarted in succession that is
>a unique group
>if the next job is not the same as the first i needed a new unique
>identifier and a total
>I wanted to get totals for these groups but had no way to group those
>by
>just did a cursor to a table and looped through and had new colun in my
>table
>clear as mud?
Hi g3000,
You don't need a cursor for this. The following single query should
produce the same results. You might wish to compare this with your
current solution and retain the version that performs best or is easiest
to maintain (dfepending on what ranks top priority in your DB).
SELECT a.Job#, SUM(a.Qty)
FROM YourTable AS a
GROUP BY a.Job#, (SELECT COUNT(DISTINCT b.Job#)
FROM YourTable AS b
WHERE b."Date" <= a."Date")
Hugo Kornelis, SQL Server MVP|||thank you Hugo,
I will try that. Didnt think about that. Looks like what I
want. I am not familiar with ranking. So ill have to look into that
later.