Showing posts with label row. Show all posts
Showing posts with label row. Show all posts

Tuesday, March 27, 2012

Binding last row in table to a label

Hi all. I have a label on my page and I want to bind it to a field in a table. The catch is that I want to bind it to the last row in the table. I think I can use the custom binding, but I don't know how to bind to the last row. Any Suggestions ?

p.s. The page is tied to an SqlDataSource that retrieves the data from the above table.

Thanks in advance.

Could you not change the datasource to only return the last row? Or did you want all the other rows as well?

What about

Label1.text = dt.Rows(dt.Rows.Count-1)("FieldName").ToString()

where dt is the datatable containing the data you are binding to.

|||

Thanks for the reply GavDraper,

but what is the type of dt, how can I use a sql server table in my code ? and what is the meaning of "FieldName" ?

|||

the type of dt is datatable. You would need to replace fieldname with the name of the field you want to pull data from. below is a very rough quick example although I'm unable to test this as im not at my development machine, you would also want to include some error handling

dim dt as new datatable()dim sqlCon as new sqlConnection(strCon)dim sqlAdp as new SqlDataAdapter()sqlAdp.SelectCommand.Connection = sqlCon()
sqlAdp.Selectcommand.CommandText ("SELECT * FROM tablename")sqlAdp.fill(dt)lbl1.Text = dt.Rows(dt.Rows.Count-1)("FieldName")
|||

I'll give it a try,

but is it possible to do it without the code behind ?

I have the label and I use databinding to bind the fields in the table using the sqldatasource, but somehow it gives me the first row in the table.

I use a stored procedure to select the data from the table and use parameters in that stored procedure. So is it possible to bind to these parameters declaratively so they would give me the fields in the last row ?

The stored procedure:

CREATE PROCEDURE dbo.createPage@.PageTitlenvarchar(300)OUTPUT, @.PageMetaDescnvarchar(300)OUTPUT,@.PageMetaWordsnvarchar(300)OUTPUT,@.PageDescnvarchar(300)OUTPUT,@.PageTemplateint OUTPUTASDECLARE @.pIdAS intSELECT @.pId =cast(SCOPE_IDENTITY()AS int)--selecting the id of the last row inserted--selecting the data from that rowSELECT PageTitle,PageMetaDesc,PageMetaWords,PageDesc,PageHTML, PageTemplate, PageSummaryHTMLFROM PagesWHERE PageId = @.pIdGO
 
|||

that stored procedure is returning the data in no particular order how can you be sure its always the last record you want? You could change the stored procedure to only return 1 record by using the TOP keyword but to make this accurate the data would have to be ordered to guarentee you will always get the correct row.

Tuesday, March 20, 2012

big task?

i have a table with 3 columns:
duration (int)
startdatetime (bigint)
userid (int)
i want to get that row's startdatetime where sum of duration becomes equal
to or greater than 1000.
how can i do that? i can only think of a cursor solution.
ThanksIn the future, instead of columnname (datatype) if you could give a real
table structure and data it would be easier to get a proper solution. I get
the feeling that this is a bit more complex that you are letting on, so you
might have to rework the code where I a TOP to include max values and
groupings, but based on the table you gave:
drop table test
go
create table test
(
duration int,
startdatetime bigint primary key,
userid int
)
go
insert into test
select 400, 500, 1
union all
select 500, 600, 1
union all
select 100, 650, 1
union all
select 100, 700, 1
go
select top 1 *
from ( select *,
(select sum(startdatetime)
from test as t2
where t2.startDateTime <= test.startDateTime) as cumulativeDuration
from test) as sums
where cumulativeDuration > 1000
Returns:
duration startdatetime userid cumulativeDuration
-- -- -- --
500 600 1 1100
----
Louis Davidson - http://spaces.msn.com/members/drsql/
SQL Server MVP
"Arguments are to be avoided: they are always vulgar and often convincing."
(Oscar Wilde)
"JY" <jy1970us@.yahoo.com> wrote in message
news:O%bHf.5429$J%6.383634@.news20.bellglobal.com...
>i have a table with 3 columns:
> duration (int)
> startdatetime (bigint)
> userid (int)
> i want to get that row's startdatetime where sum of duration becomes equal
> to or greater than 1000.
> how can i do that? i can only think of a cursor solution.
> Thanks
>
>
>|||On Fri, 10 Feb 2006 21:31:09 -0500, JY wrote:

>i have a table with 3 columns:
>duration (int)
>startdatetime (bigint)
>userid (int)
>i want to get that row's startdatetime where sum of duration becomes equal
>to or greater than 1000.
>how can i do that? i can only think of a cursor solution.
>Thanks
Hi JY,
Here's an alternative solution, based on the table and data created and
posted by Louis Davidson:
SELECT TOP 1 a.duration, a.startdatetime, a.userid,
SUM(b.duration) AS cumulativeDuration
FROM test AS a
INNER JOIN test AS b
ON b.startdatetime <= a.startdatetime
GROUP BY a.duration, a.startdatetime, a.userid
HAVING SUM(b.duration) > 1000
ORDER BY a.startdatetime
Hugo Kornelis, SQL Server MVPsql

Wednesday, March 7, 2012

Beware the UNION ALL - it can swallow rows...

Just for all you June CTPers as a warning.. I have a UNION ALL that, at random, decides to swallow row count....

Tried deleting and recreating task
Unable to Repro

Along with the buffer leaks and the looping errors.. bring on the NEXT CTP.. ! ! !

Giri,

Can you send me a package that reproduces this issue? We're unaware of any UnionAll issues with CTP15 and I'd love to fix these.

thanks

Saturday, February 25, 2012

better way to fix broken replication?

If replication ever blows up with an error like:
"The row was not found at the Subscriber when applying the replicated
command."
There is only one way I know to fix it:
Read the Last Command in the "Distribution Agent Error Details" box:
{CALL sp_MSupd_AcctHistory
(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,2005-01-01 00:00:00,7,0x0001)}
Then do a:
exec sp_browsereplcmds
and look for that same line from above. Grab the xact_seqno. Will this
always be the first row in the result set as in my testing?
Then do a:
select * from MSRepl_commands
where xact_seqno = 0x0000002C000000440001
and then delete those rows.
Is there a better way?
SQL2K SP3
TIA, ChrisR
no, insert a dummy record in the subscriber with the specific pk. Then
restart your agent.
Hilary Cotter
Looking for a SQL Server replication book?
http://www.nwsu.com/0974973602.html
Looking for a FAQ on Indexing Services/SQL FTS
http://www.indexserverfaq.com
"ChrisR" <bla@.noemail.com> wrote in message
news:umzuGUlKFHA.3132@.TK2MSFTNGP12.phx.gbl...
> If replication ever blows up with an error like:
> "The row was not found at the Subscriber when applying the replicated
> command."
> There is only one way I know to fix it:
>
> Read the Last Command in the "Distribution Agent Error Details" box:
> {CALL sp_MSupd_AcctHistory
> (NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,2005-01-01 00:00:00,7,0x0001)}
> Then do a:
> exec sp_browsereplcmds
> and look for that same line from above. Grab the xact_seqno. Will this
> always be the first row in the result set as in my testing?
> Then do a:
> select * from MSRepl_commands
> where xact_seqno = 0x0000002C000000440001
> and then delete those rows.
> Is there a better way?
>
> --
> SQL2K SP3
> TIA, ChrisR
>
|||Far too easy! ;-)
Thanks.
"Hilary Cotter" <hilary.cotter@.gmail.com> wrote in message
news:#mogudlKFHA.1476@.TK2MSFTNGP09.phx.gbl...
> no, insert a dummy record in the subscriber with the specific pk. Then
> restart your agent.
> --
> Hilary Cotter
> Looking for a SQL Server replication book?
> http://www.nwsu.com/0974973602.html
> Looking for a FAQ on Indexing Services/SQL FTS
> http://www.indexserverfaq.com
> "ChrisR" <bla@.noemail.com> wrote in message
> news:umzuGUlKFHA.3132@.TK2MSFTNGP12.phx.gbl...
>
|||What about other scenarios where thats not an option. Say the Publisher has
a column that allows NULL's, but for some lame reason the Subscriber
doesn't? A row with a NULL gets Inserted into the Publisher, but chokes out
replication when it tries to insert into the Subscriber.
"Hilary Cotter" <hilary.cotter@.gmail.com> wrote in message
news:#mogudlKFHA.1476@.TK2MSFTNGP09.phx.gbl...
> no, insert a dummy record in the subscriber with the specific pk. Then
> restart your agent.
> --
> Hilary Cotter
> Looking for a SQL Server replication book?
> http://www.nwsu.com/0974973602.html
> Looking for a FAQ on Indexing Services/SQL FTS
> http://www.indexserverfaq.com
> "ChrisR" <bla@.noemail.com> wrote in message
> news:umzuGUlKFHA.3132@.TK2MSFTNGP12.phx.gbl...
>
|||use your replication stored procedures to test for this condition and
possibly use coalesce to insert a value.
Hilary Cotter
Looking for a SQL Server replication book?
http://www.nwsu.com/0974973602.html
Looking for a FAQ on Indexing Services/SQL FTS
http://www.indexserverfaq.com
"ChrisR" <bla@.noemail.com> wrote in message
news:OhvcallKFHA.3552@.TK2MSFTNGP12.phx.gbl...
> What about other scenarios where thats not an option. Say the Publisher
has
> a column that allows NULL's, but for some lame reason the Subscriber
> doesn't? A row with a NULL gets Inserted into the Publisher, but chokes
out[vbcol=seagreen]
> replication when it tries to insert into the Subscriber.
>
> "Hilary Cotter" <hilary.cotter@.gmail.com> wrote in message
> news:#mogudlKFHA.1476@.TK2MSFTNGP09.phx.gbl...
00:00:00,7,0x0001)}
>

Better way to check row for values?

I have a group of fields that I want to check for len() = 0. If one of
them in that group is blank len()=0 then I will set some output
parameter to yes. Then the client will report to the user that they need
to complete that section.
My solution now is to set a each field to a variable and if any one of
them are 0 (using or), set the parameter.
Is there a better way to do this?
I was thinking it would be great if there was a function that would just
return true or false if any field in that function was null/len()=0
Example
IFEmpty(Field1, Field2, etc) return True
____________________________
Steven K. Lewis
Website Nation, LLC
Website Development Services
www dot Website Nation dot comyes, use NullIf in combination with Coalesce...
NullIf(CoalA, '') returns a Null if COlA = '' (empty String), else it
returns value of ColA... So NullIf(ColA, '') will return Null if ColA IS
Null, or if ColA = '' (empty)
Then compare Coalesce of all columns together
If Coalesce(NullIf(ColA, ''), NullIf(ColB, ''), NullIf(ColC, ''),
NullIf(ColD, ''), etc, ) Is Null,
-- Then at one (or more) of them is null or empty
"Steve Lewis - Website Nation" wrote:

> I have a group of fields that I want to check for len() = 0. If one of
> them in that group is blank len()=0 then I will set some output
> parameter to yes. Then the client will report to the user that they need
> to complete that section.
> My solution now is to set a each field to a variable and if any one of
> them are 0 (using or), set the parameter.
> Is there a better way to do this?
> I was thinking it would be great if there was a function that would just
> return true or false if any field in that function was null/len()=0
> Example
> IFEmpty(Field1, Field2, etc) return True
>
> --
> ____________________________
> Steven K. Lewis
> Website Nation, LLC
> Website Development Services
> www dot Website Nation dot com
>|||Cool, thanks, I will check that out. I have used NullIf before, but not
Coalesce. That looks like it will solve my problem.
____________________________
Steven K. Lewis
Website Nation, LLC
Website Development Services
www dot Website Nation dot com
On 3/9/2005 8:49 PM, CBretana wrote:
> yes, use NullIf in combination with Coalesce...
> NullIf(CoalA, '') returns a Null if COlA = '' (empty String), else it
> returns value of ColA... So NullIf(ColA, '') will return Null if ColA IS
> Null, or if ColA = '' (empty)
> Then compare Coalesce of all columns together
> If Coalesce(NullIf(ColA, ''), NullIf(ColB, ''), NullIf(ColC, ''),
> NullIf(ColD, ''), etc, ) Is Null,
> -- Then at one (or more) of them is null or empty
> "Steve Lewis - Website Nation" wrote:
>|||I believe that your suggestion will test whether all of the fields are empty
.
Whereas the original poster was trying to test for any one of the fields
being empty.
You could try something like...
create table testtable
(
colA varchar(10),
colB varchar(10)
)
go
insert into testtable values ('', '')
insert into testtable values (null, null)
insert into testtable values ('a', '')
insert into testtable values ('a', null)
insert into testtable values (null, 'a')
insert into testtable values ('', 'a')
insert into testtable values ('a', 'a')
go
select case when substring(nullif(colA, ''), 1, 1) + substring(nullif(colb,
''), 1, 1) is null then 1 else 0 end from testtable
go
drop table testtable
"CBretana" wrote:
> yes, use NullIf in combination with Coalesce...
> NullIf(CoalA, '') returns a Null if COlA = '' (empty String), else it
> returns value of ColA... So NullIf(ColA, '') will return Null if ColA IS
> Null, or if ColA = '' (empty)
> Then compare Coalesce of all columns together
> If Coalesce(NullIf(ColA, ''), NullIf(ColB, ''), NullIf(ColC, ''),
> NullIf(ColD, ''), etc, ) Is Null,
> -- Then at one (or more) of them is null or empty
> "Steve Lewis - Website Nation" wrote:
>|||Yes, I am trying to test for any one of the fields. But, between the two
if you, I think I have an answer.
____________________________
Steven K. Lewis
Website Nation, LLC
Website Development Services
www dot Website Nation dot com
On 3/9/2005 9:55 PM, Mike Gemmell wrote:
> I believe that your suggestion will test whether all of the fields are emp
ty.
> Whereas the original poster was trying to test for any one of the fields
> being empty.
> You could try something like...
> create table testtable
> (
> colA varchar(10),
> colB varchar(10)
> )
> go
> insert into testtable values ('', '')
> insert into testtable values (null, null)
> insert into testtable values ('a', '')
> insert into testtable values ('a', null)
> insert into testtable values (null, 'a')
> insert into testtable values ('', 'a')
> insert into testtable values ('a', 'a')
> go
> select case when substring(nullif(colA, ''), 1, 1) + substring(nullif(colb
,
> ''), 1, 1) is null then 1 else 0 end from testtable
> go
> drop table testtable
> "CBretana" wrote:
>|||Mike,
Right, Coalesce returns the first non-null parameter in the parameter list,
So only if all of them are null, will the whole Coalesce expression will be
null.
Concatenating the NullIfs, as you suggest, is the right answer...
"Mike Gemmell" wrote:
> I believe that your suggestion will test whether all of the fields are emp
ty.
> Whereas the original poster was trying to test for any one of the fields
> being empty.
> You could try something like...
> create table testtable
> (
> colA varchar(10),
> colB varchar(10)
> )
> go
> insert into testtable values ('', '')
> insert into testtable values (null, null)
> insert into testtable values ('a', '')
> insert into testtable values ('a', null)
> insert into testtable values (null, 'a')
> insert into testtable values ('', 'a')
> insert into testtable values ('a', 'a')
> go
> select case when substring(nullif(colA, ''), 1, 1) + substring(nullif(colb
,
> ''), 1, 1) is null then 1 else 0 end from testtable
> go
> drop table testtable
> "CBretana" wrote:
>|||OK , I see how the concatenation will work, but doesn't
CONCAT_NULL_YIELDS_NULL have to be set ON or is that ON by default?
According to books online:
When SET CONCAT_NULL_YIELDS_NULL is ON, concatenating a null value with
a string yields a NULL result. For example, SELECT 'abc' + NULL yields
NULL. When SET CONCAT_NULL_YIELDS_NULL is OFF, concatenating a null
value with a string yields the string itself (the null value is treated
as an empty string). For example, SELECT 'abc' + NULL yields abc.
____________________________
Steven K. Lewis
Website Nation, LLC
Website Development Services
www dot Website Nation dot com
On 3/10/2005 12:03 AM, CBretana wrote:
> Mike,
> Right, Coalesce returns the first non-null parameter in the parameter lis
t,
> So only if all of them are null, will the whole Coalesce expression will
be
> null.
> Concatenating the NullIfs, as you suggest, is the right answer...
>
> "Mike Gemmell" wrote:
>|||OK , i just found that is on by default:
Option Default Setting
Set nocount OFF
Set noexec OFF
Set parseonly OFF
Set concat_null_yields_null ON
Set rowcount 0
Set ansi_defaults ON
Set arithabort ON
Set showplant_text OFF
Set statistics time OFF
Set statistics 10 OFF
Set ansi_nulls ON
Set ansi_null_dflt_on ON
Set ansi_padding ON
Set ansi_warnings ON
Set cursor_close_on_commit OFF
Set implicit_transactions OFF
Set quoted_identifier ON
____________________________
Steven K. Lewis
Website Nation, LLC
Website Development Services
www dot Website Nation dot com
On 3/10/2005 12:15 AM, Steve Lewis - Website Nation wrote:
> OK , I see how the concatenation will work, but doesn't
> CONCAT_NULL_YIELDS_NULL have to be set ON or is that ON by default?
> According to books online:
> When SET CONCAT_NULL_YIELDS_NULL is ON, concatenating a null value with
> a string yields a NULL result. For example, SELECT 'abc' + NULL yields
> NULL. When SET CONCAT_NULL_YIELDS_NULL is OFF, concatenating a null
> value with a string yields the string itself (the null value is treated
> as an empty string). For example, SELECT 'abc' + NULL yields abc.
>
> ____________________________
> Steven K. Lewis
> Website Nation, LLC
> Website Development Services
> www dot Website Nation dot com
>
> On 3/10/2005 12:03 AM, CBretana wrote:
>|||Ok , this is what I have. I will test it tomorrow:
select case when substring(nullif(colA, ''), 1, 1) +
substring(nullif(colb, ''), 1, 1) is null then set @.Incomplete = 'Yes'
else set @.Incomplete = 'No' end from tblEmployee where EmployeeID =
@.EmployeeID
____________________________
Steven K. Lewis
Website Nation, LLC
Website Development Services
www dot Website Nation dot com
On 3/10/2005 12:17 AM, Steve Lewis - Website Nation wrote:
> OK , i just found that is on by default:
> Option Default Setting
> Set nocount OFF
> Set noexec OFF
> Set parseonly OFF
> Set concat_null_yields_null ON
> Set rowcount 0
> Set ansi_defaults ON
> Set arithabort ON
> Set showplant_text OFF
> Set statistics time OFF
> Set statistics 10 OFF
> Set ansi_nulls ON
> Set ansi_null_dflt_on ON
> Set ansi_padding ON
> Set ansi_warnings ON
> Set cursor_close_on_commit OFF
> Set implicit_transactions OFF
> Set quoted_identifier ON
> ____________________________
> Steven K. Lewis
> Website Nation, LLC
> Website Development Services
> www dot Website Nation dot com
>
> On 3/10/2005 12:15 AM, Steve Lewis - Website Nation wrote:
>|||Why don't you use CHECK constraints to validate the data on entry?
CREATE TABLE foo (... col VARCHAR(10) NOT NULL CHECK (col > '')...)
David Portas
SQL Server MVP
--

Better way to build a stored proc for an INSERT...

I've built a stored procedure where I'm inserting a row into two tables.
Both tables have a number of columns - and so I have to pass a rather larger
number of parameters to the stored proc. Like follows
INSERT INTO MyTable1 (MyCol1, MyCol2, ... MyCol25) VALUES (@.cParm1, @.cParm2,
... @.cParm25)
INSERT INTO MyTable2 (MyCol1, MyCol2, ... MyCol25) VALUES (@.cParm26,
@.cParm27, ... @.cParm50)
For any one row, however, at least a third of the columns are going to be
NULL, based on the value of one of the columns (a category column).
There's no opportunity to modify the table structure - it is what it is.
What I have "works", but I'm curious if there's a way that doesn't involve
as many parameters.
Thanks,
KevinKevin@.test.com wrote:
> I've built a stored procedure where I'm inserting a row into two
> tables.
> Both tables have a number of columns - and so I have to pass a rather
> larger number of parameters to the stored proc. Like follows
> INSERT INTO MyTable1 (MyCol1, MyCol2, ... MyCol25) VALUES (@.cParm1,
> @.cParm2, ... @.cParm25)
> INSERT INTO MyTable2 (MyCol1, MyCol2, ... MyCol25) VALUES (@.cParm26,
> @.cParm27, ... @.cParm50)
>
> For any one row, however, at least a third of the columns are going
> to be NULL, based on the value of one of the columns (a category
> column).
> There's no opportunity to modify the table structure - it is what it
> is. What I have "works", but I'm curious if there's a way that
> doesn't involve as many parameters.
>
> Thanks,
> Kevin
Write separate stored procedures for each "insert" type. So, let's say
your table has three logical implementations (design-issues aside), you
can write three separate insert SPs that only require the user pass
those that are asked.
The other option is to use defaults on the parameters, so if they are
not passed they default to an appropriate value:
Create Proc Test
@.Param1 INT = NULL
@.Param2 INT = NULL
as
Exec dbo.Test @.Param2 = 5
Exec dbo.Test @.Param1 = 3
Exec dbo.Test 1, 3
Exec dbo.Test
You may have to add some validation to the SP in the case where a user
leaves out a logically incorrect number of columns.
David Gugick
Imceda Software
www.imceda.com|||David,
Thanks!...you've given me some good ideas to seriously consider, especially
having 3 stored procs.
Kevin

Friday, February 24, 2012

best way to update row by row?

Hello all,
I am (dangerously) new to SQL but alas, have been appointed as the new
DB-everything (admin, programmer, designer, etc.). I have been reading
up on SQL scripting and am not sure about the most efficient way to
proceed and was hoping someone could point me in the right direction.
If anyone could point me to fairly simple, good examples of looping in
SQL script for the purposes of processing and updating data from one
database (or table(s)) to another I would appreciate it - I've been
slogging around for a while and haven't been able to find anything that
compares the methods and/or provides a clear example for emulation.
I know exactly how I would do it using a recordset in ASP to handle the
logic of looping through each record in a table but have not been able
to find "the correct way" to do this strictly in SQL - it seems people
recommend against cursors. So what do you do?
I have an example in a book that utilizes a WHILE loop based on a
variable that stores RECORDCOUNT.
There seems to be a lot of anti-cursor sentiments - though cursors are
made specifically for looping through each record (fetch)
Perhaps the answer is that it's better to update row by row using
ADO/VB.
Any input, suggestions and/or links to good tutorials are much
appreciated. I've been doing a lot of reading on my own but each new
tutorial seems to contradict the last.
mail at mahalie dot comThe Best Practice in a relational database is to use set-based processing
instead of procedural 'cursor' processing whenever possible. In other
words, do all work at once instead of 'row by row'. A simple set-based
UPDATE example
--move all employees in department 12345 to department 98765
UPDATE Employees
SET Department = '98765'
WHERE Department = '12345'

> I have an example in a book that utilizes a WHILE loop based on a
> variable that stores RECORDCOUNT.
>
This technique is probably nothing more than a pseudo-cursor. Although
technically not a cursor, performance is often similar to cursor processing.

> There seems to be a lot of anti-cursor sentiments - though cursors are
> made specifically for looping through each record (fetch)
There are times when one must resort to individual row processing. Cursors
(client or server) are appropriate in that case. However, there are many
situations where cursors can and should be avoided.

> Perhaps the answer is that it's better to update row by row using
> ADO/VB.
This is just a client-side cursor. The point being that it is often
possible to achieve the desired result in a single SQL statement on the
server side rather than any sort of server or client looping construct.
Set-based processing allows the database engine to optimize the statement as
a unit.
Hope this helps.
Dan Guzman
SQL Server MVP
"mahalie" <mahalie@.gmail.com> wrote in message
news:1134446568.289271.282450@.g43g2000cwa.googlegroups.com...
> Hello all,
> I am (dangerously) new to SQL but alas, have been appointed as the new
> DB-everything (admin, programmer, designer, etc.). I have been reading
> up on SQL scripting and am not sure about the most efficient way to
> proceed and was hoping someone could point me in the right direction.
> If anyone could point me to fairly simple, good examples of looping in
> SQL script for the purposes of processing and updating data from one
> database (or table(s)) to another I would appreciate it - I've been
> slogging around for a while and haven't been able to find anything that
> compares the methods and/or provides a clear example for emulation.
> I know exactly how I would do it using a recordset in ASP to handle the
> logic of looping through each record in a table but have not been able
> to find "the correct way" to do this strictly in SQL - it seems people
> recommend against cursors. So what do you do?
> I have an example in a book that utilizes a WHILE loop based on a
> variable that stores RECORDCOUNT.
> There seems to be a lot of anti-cursor sentiments - though cursors are
> made specifically for looping through each record (fetch)
> Perhaps the answer is that it's better to update row by row using
> ADO/VB.
> Any input, suggestions and/or links to good tutorials are much
> appreciated. I've been doing a lot of reading on my own but each new
> tutorial seems to contradict the last.
> mail at mahalie dot com
>|||Thank you for the input!
I should have pointed out that set processing is not really an option.
That is, this example wouldn't apply.
--move all employees in department 12345 to department 98765
UPDATE Employees
SET Department = '98765'
WHERE Department = '12345'
Each row in the table(s) needs to be matched to a specific row in the
other existing table, and updated (conditionally, or course!) using all
sorts of fun look ups to boot!
So it sounds like a cursor is the way to go, especially if other
methods like the row count loop are just pseudo-cursors creating the
same overhead and there's no major benefit to the ASP pages carrying
some of the logic processing burden?
For what it's worth - I'll be able to do this update without lock
issues as it's an internal set of databases and run the script when
everyone's gone!|||Please post DDL+ sample data
Look at David Portas's example , how UPDATE...FROM syntax may affect your
result.
CREATE TABLE Countries
(countryname VARCHAR(20) NOT NULL PRIMARY KEY,
capitalcity VARCHAR(20));
CREATE TABLE Cities
(cityname VARCHAR(20) NOT NULL,
countryname VARCHAR(20) NOT NULL
REFERENCES Countries (countryname),
CONSTRAINT PK_Cities
PRIMARY KEY (cityname, countryname));
INSERT INTO Countries (countryname, capitalcity) VALUES ('USA', NULL);
INSERT INTO Countries (countryname, capitalcity) VALUES ('UK', NULL);
INSERT INTO Cities VALUES ('Washington', 'USA');
INSERT INTO Cities VALUES ('London', 'UK');
INSERT INTO Cities VALUES ('Manchester', 'UK');
The MS-syntax makes it all too easy for the developer to slip-up by
writing ambiguous UPDATE...FROM statements where the JOIN criteria is
not unique on the right side of the join.
Try these two identical UPDATE statements with a small change to the
primary key in between.
UPDATE Countries
SET capitalcity = cityname
FROM Countries JOIN Cities /* evil UPDATE... FROM syntax */
ON Countries.countryname = Cities.countryname;
SELECT * FROM Countries;
ALTER TABLE Cities DROP CONSTRAINT PK_Cities;
ALTER TABLE Cities ADD CONSTRAINT PK_Cities PRIMARY KEY (countryname,
cityname);
UPDATE Countries
SET capitalcity = cityname
FROM Countries JOIN Cities /* don't do this! */
ON Countries.countryname = Cities.countryname;
SELECT * FROM Countries;
You get this from the first SELECT statement:
countryname capitalcity
-- --
UK London
USA Washington
and this from the second:
countryname capitalcity
-- --
UK Manchester
USA Washington
(though these results aren't guaranteed - that's part of the problem).
Why did the result change? The physical implementation has affected the
meaning of the code, with serious, potentially disastrous consequences.
How can you even test your code if its results are subject to change
due to the vagaries of storage, indexing and cacheing?
With the ANSI syntax there is no ambiguity. The UPDATE statement
compels the programmer to design an unambiguous assignment subquery
that returns no more than a single value.
UPDATE Countries
SET capitalcity =
(SELECT MIN(cityname)
FROM Cities
WHERE Countries.countryname = Cities.countryname);
At the very least this forces the developer to reconsider whether the
UPDATE statement makes logical sense. You might want to make an effort
to learn Standard SQL instead of a dialect that can change at any time,
which will not port, cannot be understood by other programmers, etc.
"mahalie" <mahalie@.gmail.com> wrote in message
news:1134449190.817097.83020@.z14g2000cwz.googlegroups.com...
> Thank you for the input!
> I should have pointed out that set processing is not really an option.
> That is, this example wouldn't apply.
> --move all employees in department 12345 to department 98765
> UPDATE Employees
> SET Department = '98765'
> WHERE Department = '12345'
> Each row in the table(s) needs to be matched to a specific row in the
> other existing table, and updated (conditionally, or course!) using all
> sorts of fun look ups to boot!
> So it sounds like a cursor is the way to go, especially if other
> methods like the row count loop are just pseudo-cursors creating the
> same overhead and there's no major benefit to the ASP pages carrying
> some of the logic processing burden?
> For what it's worth - I'll be able to do this update without lock
> issues as it's an internal set of databases and run the script when
> everyone's gone!
>|||mahalie wrote:
> Thank you for the input!
> I should have pointed out that set processing is not really an option.
> That is, this example wouldn't apply.
> --move all employees in department 12345 to department 98765
> UPDATE Employees
> SET Department = '98765'
> WHERE Department = '12345'
> Each row in the table(s) needs to be matched to a specific row in the
> other existing table, and updated (conditionally, or course!) using all
> sorts of fun look ups to boot!
> So it sounds like a cursor is the way to go, especially if other
> methods like the row count loop are just pseudo-cursors creating the
> same overhead and there's no major benefit to the ASP pages carrying
> some of the logic processing burden?
> For what it's worth - I'll be able to do this update without lock
> issues as it's an internal set of databases and run the script when
> everyone's gone!
Nothing you have said implies that a cursor is the best or only
solution. There's no fundamental reason why you can't write set based
code that will "match to a specific row in the other table and update
conditionally using look ups". There are many reasons to choose a set
based solution and not all of them are to do with performance and
scalability. Simplicity, ease of maintenance and portability are
usually advantages of set based code as well.
The best way to get help with your question is to post DDL, sample data
and expected results. See: http://www.aspfaq.com/etiquette.asp?id=5006
David Portas
SQL Server MVP
--|||Mahalie,
Cursors are often discouraged mainly due to the conflict with rolling back
transactions. Just as a safety precaution, use aliases instead of the
tablename.fieldname approach. This will allow you to easily replace UPDATE
with SELECT to check the result set set before you commit the cursor.
Just my twist on it,
Adam Turner
"mahalie" wrote:

> Hello all,
> I am (dangerously) new to SQL but alas, have been appointed as the new
> DB-everything (admin, programmer, designer, etc.). I have been reading
> up on SQL scripting and am not sure about the most efficient way to
> proceed and was hoping someone could point me in the right direction.
> If anyone could point me to fairly simple, good examples of looping in
> SQL script for the purposes of processing and updating data from one
> database (or table(s)) to another I would appreciate it - I've been
> slogging around for a while and haven't been able to find anything that
> compares the methods and/or provides a clear example for emulation.
> I know exactly how I would do it using a recordset in ASP to handle the
> logic of looping through each record in a table but have not been able
> to find "the correct way" to do this strictly in SQL - it seems people
> recommend against cursors. So what do you do?
> I have an example in a book that utilizes a WHILE loop based on a
> variable that stores RECORDCOUNT.
> There seems to be a lot of anti-cursor sentiments - though cursors are
> made specifically for looping through each record (fetch)
> Perhaps the answer is that it's better to update row by row using
> ADO/VB.
> Any input, suggestions and/or links to good tutorials are much
> appreciated. I've been doing a lot of reading on my own but each new
> tutorial seems to contradict the last.
> mail at mahalie dot com
>|||> I should have pointed out that set processing is not really an option.
> That is, this example wouldn't apply.
> --move all employees in department 12345 to department 98765
> UPDATE Employees
> SET Department = '98765'
> WHERE Department = '12345'
> Each row in the table(s) needs to be matched to a specific row in the
> other existing table, and updated (conditionally, or course!) using all
> sorts of fun look ups to boot!
This can easily be done in a single UPDATE statement as Uri pointed out in
his examples. I wouldn't go so far as to say that the proprietary
UPDATE...FROM syntax is 'evil' since I find it especially handy when
multiple columns are to be updated. Note that the gotchas with poorly
formulated queries that Uri pointed out apply to cursors as well.
As David suggested, please post your DDL and script so that we can perhaps
demonstrate a set-based approach for your situation.
Hope this helps.
Dan Guzman
SQL Server MVP
"mahalie" <mahalie@.gmail.com> wrote in message
news:1134449190.817097.83020@.z14g2000cwz.googlegroups.com...
> Thank you for the input!
> I should have pointed out that set processing is not really an option.
> That is, this example wouldn't apply.
> --move all employees in department 12345 to department 98765
> UPDATE Employees
> SET Department = '98765'
> WHERE Department = '12345'
> Each row in the table(s) needs to be matched to a specific row in the
> other existing table, and updated (conditionally, or course!) using all
> sorts of fun look ups to boot!
> So it sounds like a cursor is the way to go, especially if other
> methods like the row count loop are just pseudo-cursors creating the
> same overhead and there's no major benefit to the ASP pages carrying
> some of the logic processing burden?
> For what it's worth - I'll be able to do this update without lock
> issues as it's an internal set of databases and run the script when
> everyone's gone!
>|||This is a small piece of the overall project. I thought I was asking a
more theoretical quesiton - didn't want to bother you all with the
grimy details. But you asked and I'll take any help I can get, so here
we go with the DDL. Sorry if this is more info than needed - I thought
it would be easiest for anyone actually wanting to look at this to be
able to cut and paste tthe whole shebang at once...so below includes
create db, tables and sample data inserts for both databases.
Note I cannot make ANY structural changes to DB_2 - it's the backend of
a large application, I can only write to it. I can, however, make any
modifications to DB_1 necessary that would make porting the data from
it to DB_2 easier.
What I'm trying to do in pseudo-pseudocode:
FOR EACH EMPLOYEE IN DB_1..Employees
Check to see if employee exists in DB_2 using email address to match
(empID in DB_1 is just and ID field and doesn't correpsond to DB_2) -
If they don't exist, retrun an error message, move to next employee
If the employee exists, get employee number (DB_2..EM.Employee)
Look up all degrees for that employee matching DB_1..Employees.empID =
DB_1..Education.empID
For each employee, add degree
lookup DB_2 degree code by matching DB_1.Edcuation.eduDegree to
DB_2..CFGEMDegree.Description
(if the Description does not exist, add it - the code doesn't auto
increment so create number by getting last CFGEMDegree.Code, cast as
int, add 1)
add degree info DB_1..Education to DB_2..Degrees (using
DB_2.CFGEMDegree..Code value instead of DB_1..Education.eduDegree, and
DB_2..EM.Employee instead of DB_1..Education.empID).
As I mentioned, I can figure out how to do this using recordsets and
ASP, and even scripting in SQL using cursors (I think, haven't tried it
yet but it looks straight forward). But if it's both better and
possible to use set based code, please enlighten me because I don't
understand how!
I'm going to have to do similar processing for other employee related
tables - lists of project experience and licenses, but once I'm on the
path with this it should be transferrable.
Many, MANY, thanks in advance!
/*create DB_1*/
CREATE DATABASE [DB_1] ON (NAME = N'DB_1_dat', FILENAME = N'C:\Program
Files\Microsoft SQL Server\MSSQL\data\DB_1.mdf' , SIZE = 2, FILEGROWTH
= 10%) LOG ON (NAME = N'DB_1_log', FILENAME = N'C:\Program
Files\Microsoft SQL Server\MSSQL\data\DB_1.ldf' , SIZE = 2, FILEGROWTH
= 10%)
COLLATE SQL_Latin1_General_CP1_CI_AS
GO
exec sp_dboption N'DB_1', N'autoclose', N'false'
GO
exec sp_dboption N'DB_1', N'bulkcopy', N'true'
GO
exec sp_dboption N'DB_1', N'trunc. log', N'true'
GO
exec sp_dboption N'DB_1', N'torn page detection', N'true'
GO
exec sp_dboption N'DB_1', N'read only', N'false'
GO
exec sp_dboption N'DB_1', N'dbo use', N'false'
GO
exec sp_dboption N'DB_1', N'single', N'false'
GO
exec sp_dboption N'DB_1', N'autoshrink', N'false'
GO
exec sp_dboption N'DB_1', N'ANSI null default', N'false'
GO
exec sp_dboption N'DB_1', N'recursive triggers', N'false'
GO
exec sp_dboption N'DB_1', N'ANSI nulls', N'false'
GO
exec sp_dboption N'DB_1', N'concat null yields null', N'false'
GO
exec sp_dboption N'DB_1', N'cursor close on commit', N'false'
GO
exec sp_dboption N'DB_1', N'default to local cursor', N'false'
GO
exec sp_dboption N'DB_1', N'quoted identifier', N'false'
GO
exec sp_dboption N'DB_1', N'ANSI warnings', N'false'
GO
exec sp_dboption N'DB_1', N'auto create statistics', N'true'
GO
exec sp_dboption N'DB_1', N'auto update statistics', N'true'
GO
USE DB_1
GO
/* tables in DB_1 (origin of data) */
CREATE TABLE [Employees] (
[empID] [varchar] (20) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[empEmail] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
CONSTRAINT [PK_Employees] PRIMARY KEY CLUSTERED
(
[empID]
) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [Education] (
[eduID] [int] IDENTITY (1, 1) NOT NULL ,
[empID] [varchar] (20) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[eduDegree] [varchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[eduSpecialty] [varchar] (60) COLLATE SQL_Latin1_General_CP1_CI_AS
NULL ,
[eduInstitution] [varchar] (60) COLLATE SQL_Latin1_General_CP1_CI_AS
NULL ,
[eduYear] [smallint] NOT NULL CONSTRAINT [DF_Education_eduYear]
DEFAULT (0),
CONSTRAINT [FK_Education_Employees] FOREIGN KEY
(
[empID]
) REFERENCES [Employees] (
[empID]
) ON DELETE CASCADE ON UPDATE CASCADE
) ON [PRIMARY]
GO
/* Create Database DB_2 - destination of data */
CREATE DATABASE [DB_2] ON (NAME = N'ART_Data', FILENAME = N'C:\Program
Files\Microsoft SQL Server\MSSQL\Data\DB_2.mdf' , SIZE = 100,
FILEGROWTH = 10%) LOG ON (NAME = N'ART_Log', FILENAME = N'C:\Program
Files\Microsoft SQL Server\MSSQL\Data\DB_2_log.ldf' , SIZE = 9,
FILEGROWTH = 10%)
COLLATE SQL_Latin1_General_CP1_CI_AS
GO
exec sp_dboption N'DB_2', N'autoclose', N'false'
GO
exec sp_dboption N'DB_2', N'bulkcopy', N'false'
GO
exec sp_dboption N'DB_2', N'trunc. log', N'true'
GO
exec sp_dboption N'DB_2', N'torn page detection', N'true'
GO
exec sp_dboption N'DB_2', N'read only', N'false'
GO
exec sp_dboption N'DB_2', N'dbo use', N'false'
GO
exec sp_dboption N'DB_2', N'single', N'false'
GO
exec sp_dboption N'DB_2', N'autoshrink', N'false'
GO
exec sp_dboption N'DB_2', N'ANSI null default', N'false'
GO
exec sp_dboption N'DB_2', N'recursive triggers', N'false'
GO
exec sp_dboption N'DB_2', N'ANSI nulls', N'false'
GO
exec sp_dboption N'DB_2', N'concat null yields null', N'false'
GO
exec sp_dboption N'DB_2', N'cursor close on commit', N'false'
GO
exec sp_dboption N'DB_2', N'default to local cursor', N'false'
GO
exec sp_dboption N'DB_2', N'quoted identifier', N'false'
GO
exec sp_dboption N'DB_2', N'ANSI warnings', N'false'
GO
exec sp_dboption N'DB_2', N'auto create statistics', N'true'
GO
exec sp_dboption N'DB_2', N'auto update statistics', N'true'
GO
/*corresponding tables in DB_2 (destination of data) */
USE DB_2
GO
CREATE TABLE [EM] (
[Employee] [varchar] (20) COLLATE SQL_Latin1_General_CP1_CI_AS NOT
NULL ,
[LastName] [varchar] (30) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[FirstName] [varchar] (25) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[MiddleName] [varchar] (30) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
,
[EMail] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
CONSTRAINT [EMPK] PRIMARY KEY NONCLUSTERED
(
[Employee]
) WITH FILLFACTOR = 90 ON [PRIMARY]
)
GO
/*Degrees Table*/
CREATE TABLE [EMDegree] (
[RecordID] [varchar] (32) COLLATE SQL_Latin1_General_CP1_CI_AS NOT
NULL ,
[Employee] [varchar] (20) COLLATE SQL_Latin1_General_CP1_CI_AS NOT
NULL ,
[Seq] [smallint] NOT NULL CONSTRAINT [DF__EMDegree__Seq__04659998]
DEFAULT (0),
[Degree] [varchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[Specialty] [varchar] (60) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[Institution] [varchar] (60) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
,
[YearEarned] [smallint] NOT NULL CONSTRAINT
[DF__EMDegree__YearEa__0559BDD1] DEFAULT (0),
CONSTRAINT [EMDegreePK] PRIMARY KEY NONCLUSTERED
(
[RecordID]
) WITH FILLFACTOR = 90 ON [PRIMARY] ,
CONSTRAINT [FK_EMDegree_Employee_EM] FOREIGN KEY
(
[Employee]
) REFERENCES [EM] (
[Employee]
)
) ON [PRIMARY]
GO
/*Degree Codes Table */
CREATE TABLE [CFGEMDegree] (
[Code] [varchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[Description] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT
NULL ,
CONSTRAINT [CFGEMDegreePK] PRIMARY KEY NONCLUSTERED
(
[Code]
) WITH FILLFACTOR = 90 ON [PRIMARY]
) ON [PRIMARY]
GO
USE DB_1
GO
/*sample data, for DB_1 */
/*employees*/
INSERT INTO [Employees]
([empID],[empEmail])VALUES('CathyG','cat
hyg@.domain.com')
INSERT INTO [Employees]
([empID],[empEmail])VALUES('CharlesM','c
harlesm@.domain.com')
INSERT INTO [Employees]
([empID],[empEmail])VALUES('DennisC','de
nnisc@.domain.com')
INSERT INTO [Employees]
([empID],[empEmail])VALUES('DorisD','Dor
isD@.domain.com')
INSERT INTO [Employees]
([empID],[empEmail])VALUES('jenniferp','
jenniferp@.domain.com')
INSERT INTO [Employees]
([empID],[empEmail])VALUES('MahalieP','m
ahaliep@.domain.com')
INSERT INTO [Employees]
([empID],[empEmail])VALUES('mercedesd','
mercedesd@.domain.com')
INSERT INTO [Employees]
([empID],[empEmail])VALUES('TeresaN','te
resan@.domain.com')
/*degrees*/
INSERT INTO [Education]
([empID],[eduDegree],[eduSpecialty],[edu
Institution],[eduYear])VALUES('CharlesM'
,'MFA','Birds','Yale
Design School',99)
INSERT INTO [Education]
([empID],[eduDegree],[eduSpecialty],[edu
Institution],[eduYear])VALUES('mercedesd
','BS','Gymnastics','Yale',2000)
INSERT INTO [Education]
([empID],[eduDegree],[eduSpecialty],[edu
Institution],[eduYear])VALUES('DorisD','
BS','comp
sci','uw',1985)
INSERT INTO [Education]
([empID],[eduDegree],[eduSpecialty],[edu
Institution],[eduYear])VALUES('DorisD','
Masters','architecture','uw',1999)
INSERT INTO [Education]
([empID],[eduDegree],[eduSpecialty],[edu
Institution],[eduYear])VALUES('jenniferp
','AA','arch','yale',2004)
INSERT INTO [Education]
([empID],[eduDegree],[eduSpecialty],[edu
Institution],[eduYear])VALUES('TeresaN',
'BA','Urban
Planning','U of W',1975)
INSERT INTO [Education]
([empID],[eduDegree],[eduSpecialty],[edu
Institution],[eduYear])VALUES('TeresaN',
'BA','Architecture','U
of W',1985)
INSERT INTO [Education]
([empID],[eduDegree],[eduSpecialty],[edu
Institution],[eduYear])VALUES('MahalieP'
,'BA','Jargon','U
of W',1998)
INSERT INTO [Education]
([empID],[eduDegree],[eduSpecialty],[edu
Institution],[eduYear])VALUES('MahalieP'
,'Masters','Bologne','MIT',2002)
USE DB_2
GO
/*sample data, for DB_2 */
/*employees*/
INSERT INTO [EM]
([Employee],[LastName],[FirstName],[Midd
leName],[EMail])VALUES('01416','Goldmeir
','Cathy','M','CathyG@.domain.com')
INSERT INTO [EM]
([Employee],[LastName],[FirstName],[Midd
leName],[EMail])VALUES('00001','Maple','
Charles','R','charlesm@.domain.com')
INSERT INTO [EM]
([Employee],[LastName],[FirstName],[Midd
leName],[EMail])VALUES('00002','Carter',
'Dennis','Richard','dennisc@.domain.com')
INSERT INTO [EM]
([Employee],[LastName],[FirstName],[Midd
leName],[EMail])VALUES('00101','Day','Do
ris','E','DorisD@.domain.com')
INSERT INTO [EM]
([Employee],[LastName],[FirstName],[Midd
leName],[EMail])VALUES('00201','Peterson
','Jennifer','May','jenniferp@.domain.com')
INSERT INTO [EM]
([Employee],[LastName],[FirstName],[Midd
leName],[EMail])VALUES('00005','Porter',
'Mahalie','M','MahalieP@.domain.com')
INSERT INTO [EM]
([Employee],[LastName],[FirstName],[Midd
leName],[EMail])VALUES('00203','Davidson
','Mercedes','Lynn','mercedesd@.domain.com')
INSERT INTO [EM]
([Employee],[LastName],[FirstName],[Midd
leName],[EMail])VALUES('00007','Spencer'
,'Thomas','John','ThomasS@.domain.com')
INSERT INTO [EM]
([Employee],[LastName],[FirstName],[Midd
leName],[EMail])VALUES('00302','Norton',
'Teresa','Ann','TeresaN@.domain.com')
INSERT INTO [EM]
([Employee],[LastName],[FirstName],[Midd
leName],[EMail])VALUES('00009','Smithfie
ld','Herbert','James','HerbertS@.domain.com')
/*degrees*/
INSERT INTO [EMDegree]
([RecordID],[Employee],[Degree],[Special
ty],[Institution],[YearEarned])VALUES('0
02011','01416','01','Architecture','Univ
ersity
of Virginia',1985)
INSERT INTO [EMDegree]
([RecordID],[Employee],[Degree],[Special
ty],[Institution],[YearEarned])VALUES('0
02012','00001','01','Interior
Design','University of North Carolina',1996)
INSERT INTO [EMDegree]
([RecordID],[Employee],[Degree],[Special
ty],[Institution],[YearEarned])VALUES('0
00021','00002','01','Art
History','Univeristy of San Diego',1962)
INSERT INTO [EMDegree]
([RecordID],[Employee],[Degree],[Special
ty],[Institution],[YearEarned])VALUES('0
00022','00002','02','Architecture','Penn
sylvannia
State University',1970)
INSERT INTO [EMDegree]
([RecordID],[Employee],[Degree],[Special
ty],[Institution],[YearEarned])VALUES('0
00031','00101','01','Design','George
Mason University',1992)
INSERT INTO [EMDegree]
([RecordID],[Employee],[Degree],[Special
ty],[Institution],[YearEarned])VALUES('A
DMIN1024963974101','00101','03','Archite
cture','Virginia
State University',1995)
INSERT INTO [EMDegree]
([RecordID],[Employee],[Degree],[Special
ty],[Institution],[YearEarned])VALUES('S
ANDERSON1012487091374','00101','02','Civ
il
Engineering','University of Florida',1982)
INSERT INTO [EMDegree]
([RecordID],[Employee],[Degree],[Special
ty],[Institution],[YearEarned])VALUES('S
ANDERSON1012487091424','00201','01','Str
uctural
Engineering','University of Florida',1985)
INSERT INTO [EMDegree]
([RecordID],[Employee],[Degree],[Special
ty],[Institution],[YearEarned])VALUES('S
ANDERSON1012487091474','00302','01','Str
uctural
Engineering','College of William and Mary',1988)
INSERT INTO [EMDegree]
([RecordID],[Employee],[Degree],[Special
ty],[Institution],[YearEarned])VALUES('S
ANDERSON1012854189480','00009','01','Soc
iology','Old
Dominion University',1987)
/*degrees code table*/
INSERT INTO [CFGEMDegree] ([Code],[Description])VALUES('01','Bache
lor
of Arts')
INSERT INTO [CFGEMDegree] ([Code],[Description])VALUES('02','Bache
lor
of Science')
INSERT INTO [CFGEMDegree] ([Code],[Description])VALUES('03','Bache
lor
of Architecture')
INSERT INTO [CFGEMDegree] ([Code],[Description])VALUES('04','Maste
rs of
Arts')
INSERT INTO [CFGEMDegree] ([Code],[Description])VALUES('05','Maste
rs of
Science')|||mahalie wrote:

> This is a small piece of the overall project. I thought I was asking a
> more theoretical quesiton - didn't want to bother you all with the
> grimy details. But you asked and I'll take any help I can get, so here
> we go with the DDL. Sorry if this is more info than needed - I thought
> it would be easiest for anyone actually wanting to look at this to be
> able to cut and paste tthe whole shebang at once...so below includes
> create db, tables and sample data inserts for both databases.
> Note I cannot make ANY structural changes to DB_2 - it's the backend of
> a large application, I can only write to it. I can, however, make any
> modifications to DB_1 necessary that would make porting the data from
> it to DB_2 easier.
> What I'm trying to do in pseudo-pseudocode:
> FOR EACH EMPLOYEE IN DB_1..Employees
> Check to see if employee exists in DB_2 using email address to match
> (empID in DB_1 is just and ID field and doesn't correpsond to DB_2) -
> If they don't exist, retrun an error message, move to next employee
> If the employee exists, get employee number (DB_2..EM.Employee)
> Look up all degrees for that employee matching DB_1..Employees.empID =
> DB_1..Education.empID
> For each employee, add degree
> lookup DB_2 degree code by matching DB_1.Edcuation.eduDegree to
> DB_2..CFGEMDegree.Description
> (if the Description does not exist, add it - the code doesn't auto
> increment so create number by getting last CFGEMDegree.Code, cast as
> int, add 1)
> add degree info DB_1..Education to DB_2..Degrees (using
> DB_2.CFGEMDegree..Code value instead of DB_1..Education.eduDegree, and
> DB_2..EM.Employee instead of DB_1..Education.empID).
> As I mentioned, I can figure out how to do this using recordsets and
> ASP, and even scripting in SQL using cursors (I think, haven't tried it
> yet but it looks straight forward). But if it's both better and
> possible to use set based code, please enlighten me because I don't
> understand how!
> I'm going to have to do similar processing for other employee related
> tables - lists of project experience and licenses, but once I'm on the
> path with this it should be transferrable.
>
> Many, MANY, thanks in advance!
>
This is an excellent example of how important it is to "think in SQL".
You've conceptualized the problem in terms of procedural steps and that
mindset unfortunately doesn't help you to write efficient code in SQL's
declarative language. That's why you thought of using a cursor. My
advice is always that only experts should write cursors. Only when you
master "real" SQL do you gain the knowledge and experience to judge
when a cursor makes sense. Until then, it's probably safest to assume
that a cursor is the wrong solution. OK, that's the sermon over with...
:-).
You have at least two steps it seems. 1) Insert the missing degree
codes in DB2. 2) Return a result set containing employee id, email and
the DB2 degree code. We know there are two steps because INSERTs are
always separate operations to SELECTs.
The INSERT is the only tricky part. Given that your degree names in DB1
and DB2 aren't very comparable I'm not clear how you want to handle
them. Possibly you'll need to review the data by eye and decide exactly
what codes are new ones and what already exist. Given that you want to
automate it I'll leave the precise logic to you but here's a partial
exaple to prove that it's possible. Notice that the temp table doesn't
use a cursor - it just helps us generate the code. (In SQL2005 there's
a much neater solution without a temp table, but I'm assuming 2000
here).
DECLARE @.t TABLE (description VARCHAR(50) NOT NULL PRIMARY KEY) ;
/* Pull the missing degrees */
INSERT INTO @.t (description)
SELECT DISTINCT D1.edudegree
FROM DB_1.dbo.education AS D1
LEFT JOIN DB_2.dbo.cfgemdegree AS D2
ON D2.description =
CASE D1.edudegree
WHEN 'BS' THEN 'Bachelor of Science'
WHEN 'BA' THEN 'Bachelor of Arts'
/* ... etc */
ELSE D1.edudegree
END
WHERE D2.code IS NULL ;
/* Generate the code and insert */
INSERT INTO DB_2.dbo.cfgemdegree (description, code)
SELECT T1.description,
RIGHT('0'+CAST(COUNT(*)+
(SELECT CAST(MAX(code) AS INT)
FROM DB_2.dbo.cfgemdegree) AS VARCHAR(2)),2) AS code
FROM @.t AS T1, @.t AS T2
WHERE T1.description >= T2.description
GROUP BY T1.description ;
Once you've sorted out the codes, the main part of the query is easy.
I'm assuming that you have matching descriptions for the degrees in
each database at this stage. If not, then you'll want to repeat
something like the CASE expression in the above INSERT. Alternatively
it might be easier to create an intermediate table to perform the
translation degree code -> description.
SELECT E1.empid, E1.empemail,
CASE WHEN E2.employee IS NULL
THEN 'Error!'
ELSE 'OK'
END AS emp_exists,
E2.employee,
D2.code
FROM DB_1.dbo.employees AS E1
LEFT JOIN DB_2.dbo.em AS E2
ON E1.empemail = E2.email
LEFT JOIN DB_1.dbo.Education AS D1
ON E1.empid = D1.empid
LEFT JOIN DB_2.dbo.cfgemdegree AS D2
ON D2.description = D1.edudegree ;
Hope this helps.
David Portas
SQL Server MVP
--|||David, thanks - sermon appreciated and your examples are exactly what I
was trying to get at without knowing what I was looking for. My
scripting background must be pretty obvious!
I'd just finished writing a temp table with new codes and distinct
degree types to UNION with the cfgemdegree table when I read your
resonse so I do think I'm not beyond hope.
All the aliases and joins have my head spinning but I think I
understand!
THANKS!!
Would it be worth creating a view that includes the
DB_2.dbo.cfgemdegree description in the DB_2.dbo.emdegree table to make
the joins a little more comprehensible or would that be more of a
maintenance issue? E.g. what's the best practice in a case like this?

Best Way To Update Existing Rows

IUpdating existing rows in a SQL server 2005 destination table

--I have a CSV file and every row needs to perform an update on a production table

The most straight forward is to use an OLEDB Command Data Flow Transformation Object that sends one SQL statement per row coming in. How do I configure this object ?

That might be okay if you've only got a small number of updates, however if you've got a large set, I prefer landing this set to a temporary table and then doing Set based updates in a following Execute SQL task. Can you please tell me how I can set up the Execute SQL Task to do set based updates in the Control flow?

thanks in advance

Dave

Mr Pro Tools wrote:

IUpdating existing rows in a SQL server 2005 destination table

--I have a CSV file and every row needs to perform an update on a production table

The most straight forward is to use an OLEDB Command Data Flow Transformation Object that sends one SQL statement per row coming in. How do I configure this object ?

I assume you can write SQL, right?

All explained here: http://msdn2.microsoft.com/en-us/library/ms141138.aspx

Mr Pro Tools wrote:

That might be okay if you've only got a small number of updates, however if you've got a large set, I prefer landing this set to a temporary table and then doing Set based updates in a following Execute SQL task. Can you please tell me how I can set up the Execute SQL Task to do set based updates in the Control flow?

thanks in advance

Dave

Again, I assume you can write SQL. Just paste your SQL into the 'SQL Statement' proeprty of the Execute SQL Task.

-Jamie

|||

Thanks Jamie

First method works --Profiler is telling me its taking about a second per update

but is too slow as I have 900,000 records to update across two tables each having 7 million records which will take

889,641 records in the file supplied / 3600 per hour (1 per second)

= 250 hours

= 10 days

the Excecute SQL task looks like another option and sure I can paste into the SQL Statement window my sproc Exec dbo.MySproc ?,?

How do I map ?,? to each row in the Execute SQL Task--in other words what are the main properties I have to set for row by row processing and is it much faster than the OLE DB Command Transformation method --which is nice and simple and slow

thanks in advance

Dave

|||

Mr Pro Tools wrote:

Thanks Jamie

First method works --Profiler is telling me its taking about a second per update

but is too slow as I have 900,000 records to update across two tables each having 7 million records which will take

889,641 records in the file supplied / 3600 per hour (1 per second)

= 250 hours

= 10 days

the Excecute SQL task looks like another option and sure I can paste into the SQL Statement window my sproc Exec dbo.MySproc ?,?

How do I map ?,? to each row in the Execute SQL Task--in other words what are the main properties I have to set for row by row processing and is it much faster than the OLE DB Command Transformation method --which is nice and simple and slow

thanks in advance

Dave

I'm confused (seems to happen alot these days ) Why are you trying to map any columns at all using '?' ?

All you have to do is load the data into a temporary staging area (using OLE DB Destination) and then issue a SQL statement along the lines of:

UPDATE t

SET t.<col> = te.<col> ,......

FROM target t INNER JOIN temp te ON <some join columns>

Also, if OLE DB Command really is taking one second per row then your bottleneck is not the OLE DB Comamnd. its something else.

-Jamie

|||

Mr Pro Tools wrote:

How do I map ?,? to each row in the Execute SQL Task--in other words what are the main properties I have to set for row by row processing and is it much faster than the OLE DB Command Transformation method --which is nice and simple and slow

Dave,

The OLEDB command is just slow becasue performs the same command in a row by row basis. The intention of using a Execute SQL task is to be able to perform execute a SQL command over a set of rows at once. What Jamie is sugesting is to push the rows in your CSV file to an staging table and then, in control flow to issue un Update stament against your target table using the staging table rows. That would be a one time update.

|||

UPDATE t

SET t.<col> = te.<col> ,......

FROM target t INNER JOIN temp te ON <some join columns>

Yeah that is simple enough what Im getting at is can the Execute SQL Task do row by row processing like the DTS DDQ task and how do set the properties if so

In my case the updates will only occur if one of columns in the temp staging table has an particular value in a column

If it has --we do the update otherwise do a delete

thats why I had ? as parameters for a store prod

|||

No, the Execute SQL Task does not do row-by-row processing. As already established, that's what the OLE DB Command does.

-Jamie

Sunday, February 19, 2012

Best way to select a Constant String from a Table ?

Hi,
What is the best way to generate a constant String from a Table (Only 1 row)
.
I have some sql statements returning a few rows. I want to also return a row
with a Constant String along with this sql statement..
e.g.
Select * from orders
Union
Select 'End of Order Select' from '
I can try selecting it from orders table, but this should return only one ro
w.
Any ideas ?
- AnandSorry for the trouble, found out the answer that I can just do
Select 'End of Order Select'
"S Anand" wrote:

> Hi,
> What is the best way to generate a constant String from a Table (Only 1 ro
w).
> I have some sql statements returning a few rows. I want to also return a r
ow
> with a Constant String along with this sql statement..
> e.g.
> Select * from orders
> Union
> Select 'End of Order Select' from '
> I can try selecting it from orders table, but this should return only one
row.
> Any ideas ?
> --
> - Anand|||hi Anand
This will work fine if you are note selecting any value from a table. If u
require a value
from a table along with a constant value, then u require to do like this:
SELECT TOP 1 'Const Value', <COLUMNS> FROM <TABLE>
you query can be modified as
Select * from orders
Union ALL
Select 'End of Order Select'
try using UNION ALL if u definately want the text to be displayed.
in case of UNION the second table will not display a value if the same value
exists
in the main table.
Hope this gives u a better picture
best Regards,
Chandra
http://chanduas.blogspot.com/
http://groups.msn.com/SQLResource/
---
"S Anand" wrote:
> Sorry for the trouble, found out the answer that I can just do
> Select 'End of Order Select'
> "S Anand" wrote:
>|||A few comments:

> Select 'End of Order Select'
Use square brackets of double-quotes around the produced column name instead
. The column you produce
in the result is an identifier and non-standard identifiers are delimited wi
th double-quotes in SNAI
SQL (and SQL Server) and SQL Server also allow double-quotes. Why SQL Server
allow single quotes for
identifiers in this particular case is beyond my understanding, very strange
..
Don't do SELECT *. It might just have been an example, but imagine of the ta
ble structure changes
and you add or remove columns. The UNION won't work.
Also, don't expect the SELECT with a constant to come last unless you do an
ORDER BY for the UNION.
Tibor Karaszi, SQL Server MVP
http://www.karaszi.com/sqlserver/default.asp
http://www.solidqualitylearning.com/
"S Anand" <x@.hotmail.com> wrote in message
news:81178FBE-0B61-411E-8836-D01240F81227@.microsoft.com...
> Sorry for the trouble, found out the answer that I can just do
> Select 'End of Order Select'
> "S Anand" wrote:
>

best way to run 45 queries in a row?

Hi,
I have created 45 queries that I need to run which will seperate and
stratify data. Each one has to be run one after the other. Right now I sit
there and muanually run them in the SQL Query Analyzer screen. Is there
something I can create to run them automatically, one after the other?
Thanks
If you have to do this more than once you can create a multistep Job or a DTS
package
http://sqlservercode.blogspot.com/
"John Jasper" wrote:

> Hi,
> I have created 45 queries that I need to run which will seperate and
> stratify data. Each one has to be run one after the other. Right now I sit
> there and muanually run them in the SQL Query Analyzer screen. Is there
> something I can create to run them automatically, one after the other?
> Thanks
|||You could copy and paste them all into one stored procedure, with some error
handling thrown in to exit and alert you if one failed...
Kevin Hill
President
3NF Consulting
www.3nf-inc.com/NewsGroups.htm
"John Jasper" <JohnJasper@.discussions.microsoft.com> wrote in message
news:74DA6630-0986-4014-AE2E-DACEDF9200D9@.microsoft.com...
> Hi,
> I have created 45 queries that I need to run which will seperate and
> stratify data. Each one has to be run one after the other. Right now I
> sit
> there and muanually run them in the SQL Query Analyzer screen. Is there
> something I can create to run them automatically, one after the other?
> Thanks

best way to run 45 queries in a row?

Hi,
I have created 45 queries that I need to run which will seperate and
stratify data. Each one has to be run one after the other. Right now I sit
there and muanually run them in the SQL Query Analyzer screen. Is there
something I can create to run them automatically, one after the other?
ThanksIf you have to do this more than once you can create a multistep Job or a DT
S
package
http://sqlservercode.blogspot.com/
"John Jasper" wrote:

> Hi,
> I have created 45 queries that I need to run which will seperate and
> stratify data. Each one has to be run one after the other. Right now I si
t
> there and muanually run them in the SQL Query Analyzer screen. Is there
> something I can create to run them automatically, one after the other?
> Thanks|||You could copy and paste them all into one stored procedure, with some error
handling thrown in to exit and alert you if one failed...
Kevin Hill
President
3NF Consulting
www.3nf-inc.com/NewsGroups.htm
"John Jasper" <JohnJasper@.discussions.microsoft.com> wrote in message
news:74DA6630-0986-4014-AE2E-DACEDF9200D9@.microsoft.com...
> Hi,
> I have created 45 queries that I need to run which will seperate and
> stratify data. Each one has to be run one after the other. Right now I
> sit
> there and muanually run them in the SQL Query Analyzer screen. Is there
> something I can create to run them automatically, one after the other?
> Thanks

best way to run 45 queries in a row?

Hi,
I have created 45 queries that I need to run which will seperate and
stratify data. Each one has to be run one after the other. Right now I sit
there and muanually run them in the SQL Query Analyzer screen. Is there
something I can create to run them automatically, one after the other?
ThanksIf you have to do this more than once you can create a multistep Job or a DTS
package
http://sqlservercode.blogspot.com/
"John Jasper" wrote:
> Hi,
> I have created 45 queries that I need to run which will seperate and
> stratify data. Each one has to be run one after the other. Right now I sit
> there and muanually run them in the SQL Query Analyzer screen. Is there
> something I can create to run them automatically, one after the other?
> Thanks|||You could copy and paste them all into one stored procedure, with some error
handling thrown in to exit and alert you if one failed...
--
Kevin Hill
President
3NF Consulting
www.3nf-inc.com/NewsGroups.htm
"John Jasper" <JohnJasper@.discussions.microsoft.com> wrote in message
news:74DA6630-0986-4014-AE2E-DACEDF9200D9@.microsoft.com...
> Hi,
> I have created 45 queries that I need to run which will seperate and
> stratify data. Each one has to be run one after the other. Right now I
> sit
> there and muanually run them in the SQL Query Analyzer screen. Is there
> something I can create to run them automatically, one after the other?
> Thanks

best way to retrieve one row for use in code

i have a SQL backend and some of the data in my tables is more or less configuration data and some times i only want to pull one row of data which i can do just fine with a SQL query but whats the best method to pull it.

assume i have a query like this.

Select A, B, C from Table1 where ID=xyz

whats the easiest way to get A, B and C in to string variables?

I know i can use the sqldatasource control but i just feel there is too much overhead there.

whats your suggestions?

Thanks

Justin

I suggest that you use aSqlDataReader.

HTH,
Ryan

Sunday, February 12, 2012

Best way to do this query

I have a Customer table and an Events table. Whenever a customer attends an
event, a row is added to the Events table, which has CustomerID, EventName
and EventDate fields.
I want a query that returns all the customers but only the most recently
attended event. In other words, I want the query to ignore events other than
the most recently attended by each customer.
The (simplified) tables are:
Customer:
ID
Name
Events:
ID
CustomerID
EventName
EventDate
Any suggestions for the best way to do this?
TimTim,
You could use something like this:
(Untested)
Select Customer.ID, Customer.Name, Events.ID, Events.EventName,
Events.EventDate
>From Customer
Join Events on Customer.ID = Events.CustomerID
Where Events.EventDate =
(Select Max(Events2.EventDate) From Events Events2 Where
Events2.CustomerID = Customer.CustomerID)
HTH
Barry|||"Barry" <barry.oconnor@.singers.co.im> wrote in message
news:1129053565.927048.54860@.o13g2000cwo.googlegroups.com...

> Select Customer.ID, Customer.Name, Events.ID, Events.EventName,
> Events.EventDate
> Join Events on Customer.ID = Events.CustomerID
> Where Events.EventDate =
> (Select Max(Events2.EventDate) From Events Events2 Where
> Events2.CustomerID = Customer.CustomerID)
Good suggestion. Thanks.
Tim

Friday, February 10, 2012

best way to compare last row with new insert

Hi !
for MS SQL 2000

I need an UsersHistory Table where i cannot INSERT 2 rows one after the other with the same user.name

I can get

Bob
David
Bob

but not

Bob
Bob
David

something like an INDEX on rows
or
INSERT INTO UsersHistory (name) VALUES ('bob') IF MAX(name) <> 'bob' ?

what is the best way to do it ?

thank youYou need some other column to order by, say a datetime. it could store when the user last logged in/logged out/whatever. Why? because the physical order of rows in a table has no meaning. Since you are storing a history, the thing you want to order by is a time, so you need a datetime column.

Then you could do something like this:

-- assumes you already have a username in a @.name variable
declare @.time datetime
select @.time = max(LoggedInAt) from UsersHistory

if not exists(select * from UsersHistory where LoggedInAt=@.time and UserName=@.name)
begin
insert into UsersHistory (UserName, LoggedInAt) values (@.name, getdate())
end|||I have allready that datetime column = getdate()

but i dont understand the meaning of your query , if the last user row is Bob the next row cannot be Bob, it doesnt depend on the DateTime it can be 10 minutes ... one year
I must have an history of LastUsers for certains events in the database, the LastUser is the Last one as long as nobody do something and replace the last one (I know my english is terrific ! :-))

the last inserted row is also the MAX(id)

thanks a lot Jezemine|||Do something like:

INSERT INTO UsersHistory (name) VALUES ('bob') IF (SELECT fname from UsersHistory where id = max(id)) <> 'bob'

Note: not actual code

best way to combine columns

Hi all,

I have a table with multiple rows with the same ID.

a) How do I combine all columns into one row with the same ID?

b) Is this better to do the combine in the store procedure/trigger or a sub that involked by some sort of datarepeater, datagrid controls?

Since I am trying to brush up my sql. I appreciate any examples on top of conceptual solution.

Thanks

I take that my question is not so clear so here is the example of what I wanted to do:

I have a sql 2000 table like this:

ID col1 col2

7777 itemx 12/02/07 00:00:10

7777 itemy 12/02/07 10:00:00

7777 itemz 12/02/07 12:10:60

8888 itemA 12/02/07 01:01:00

888 itemB 12/02/07 02:00:00

..........................................

I like to combine all rows with the same ID together like the followings:

7777 itemx itemy itemz 12/02/07

888 itemA itemB...................

The question has 3 parts:

1) what is the best way to do this? using trigger/stored procedure or just a vb sub with somesort of datarepeater, datalist controls

2) can you show me some examples of each way if any?

3) Can crystal report do something like this?

I am open to create another table or just plain writting them out on page.

Thanks

|||

Some one mentioned to me that 'trigger' could cause some confusion in reading the question. So , please do skip the trigger part.

|||

Depending on how many records will be pulled out, you could do it at the report level or at the DB level. You could write a function that takes the ID as parameter and returns a concatenated string for items and use the function in the SELECT.

SELECT Id, dbo.fnGetItems(ID), col2...

FROM ...

and create the function with a SELECT as

SELECT @.val = ISNULL(@.val,'') + ' ' + Convert(Varchar, col2) FROM YourTable WHERE ID = @.Id

and return the @.val.

|||

Thanks ndinakar. Anyone has any other solutions/ideas or clearer/complete solution? thanks

|||

Hi tvfoto,

This depends on if this table has a primary key.

If yes, I would suggest you read everything into a DataSet. Process the data combination

within the DataSet and update it back to the server, because in the .NET code, you will

have better flexibility for the combination logic.

If the table doesn't have a primary key, as ndinakar suggested, you can use some stored

procedure to achieve this.

HTH. If this does not answer you question, please feel free to mark it as Not Answered and post your reply. Thanks!

|||

THis table does not have a primary key. The following code works, however I dont know how to seperate them out as individual columns so I can give them a proper heading. Any suggestion? Thanks

//my user function.

create functionGetItems(@.mId int)

returns varchar(1000)As

Begin

declare @.values varchar(1000)

Set @.values=''

Select @.values=@.values+','+ myItemColumnName from myTable whereID=@.mId

return @.values

End

Go

//my aspx code

<

body><formid="form1"runat="server"><div><asp:SqlDataSourceID="SqlDataSource1"runat="server"ConnectionString="<%$ ConnectionStrings:myTableConnectionString %>"SelectCommand="SELECT DISTINCT [ID],dbo.GetItems(ID) as [xyzValues] FROM [myTable] "></asp:SqlDataSource>

<

asp:RepeaterID="Repeater1"runat="server"DataSourceID="SqlDataSource1">

<HeaderTemplate><tablestyle="background:#ebebeb"><tr><tdcolspan="5"> </td></tr><trstyle="text-align:left; background:yellow"><th>ID</th><th> </th><th>item1,item2,item3,item4, item5...</h>///////header for different items here...not a good way

</tr>

</HeaderTemplate><ItemTemplate><tr><tdstyle="width:25px"><%#DataBinder.Eval(Container.DataItem,"ID")%></td>

<td> </td><td><%#DataBinder.Eval(Container.DataItem,"xzyValues")%></td>.................................

</div></form></body>

Best way for a Set-based query

I have a database where each row has a set of keywords separated by
commas eg .

ROW 1 ID,<other columns>,"green,hat,man,boat"
ROW 2 ID,<other columns>,"green,boat,seaside"
ROW 3 ID,<other columns>,"red,hat"

I want users to be able to find similar records to the one they are
looking it (this is art BTW). ie if they are looking at row 1 and
click "Find Similar Works of Art" I want to do a query where I find
records that have a commonality of keywords and obviously the ones
that match the most keywords should be shown first. The keywords are
currently just stored comma-separated in a single column but I am not
attached to this. Nor are they guaranteed to come in any order (ie
they are not alpha sorted) but they could be.

Number of records is around 15000 on a hosted server.

Any tips for best query/algorithm/data storage to achieve this? or
references to useful sources?

Thanks,
RBRoland Burr wrote:

> I have a database where each row has a set of keywords separated by
> commas eg .
> ROW 1 ID,<other columns>,"green,hat,man,boat"
> ROW 2 ID,<other columns>,"green,boat,seaside"
> ROW 3 ID,<other columns>,"red,hat"
> I want users to be able to find similar records to the one they are
> looking it (this is art BTW). ie if they are looking at row 1 and
> click "Find Similar Works of Art" I want to do a query where I find
> records that have a commonality of keywords and obviously the ones
> that match the most keywords should be shown first. The keywords are
> currently just stored comma-separated in a single column but I am not
> attached to this. Nor are they guaranteed to come in any order (ie
> they are not alpha sorted) but they could be.
> Number of records is around 15000 on a hosted server.
> Any tips for best query/algorithm/data storage to achieve this? or
> references to useful sources?
> Thanks,
> RB

normally you break the keywords out into a child table, so that you have two
tables (there may be typos in my SQL, this is off the top of my head):

CREATE TABLE artwork (
ID char(10) PRIMARY KEY,
...other columns...
)

CREATE TABLE keywords (
ID char(10) FOREIGN KEY REFERENCES artwork(ID),
keyword char(10)
)

Index on keyword and the SQL queries should write themselves.

--
Kenneth Downs
Secure Data Software, Inc.
(Ken)nneth@.(Sec)ure(Dat)a(.com)|||Roland Burr (rburr49@.hotmail.com) writes:
> I have a database where each row has a set of keywords separated by
> commas eg .
> ROW 1 ID,<other columns>,"green,hat,man,boat"
> ROW 2 ID,<other columns>,"green,boat,seaside"
> ROW 3 ID,<other columns>,"red,hat"
> I want users to be able to find similar records to the one they are
> looking it (this is art BTW). ie if they are looking at row 1 and
> click "Find Similar Works of Art" I want to do a query where I find
> records that have a commonality of keywords and obviously the ones
> that match the most keywords should be shown first. The keywords are
> currently just stored comma-separated in a single column but I am not
> attached to this. Nor are they guaranteed to come in any order (ie
> they are not alpha sorted) but they could be.

I'm glad to hear that you are not attached to the format, because
this sort of format, is really ugly to work with in SQL, as it
violates a basic principle for relational database design. As Kenneth
said, store the keywords as rows.

Find the number of matches given one item would be as easy as this:

SELECT k1.id, COUNT(*)
JOIN keywords k1
WHERE EXISTS (SELECT *
FROM keywordss k2
WHERE k2.id = @.currentid
AND k1.keyword = k2.keyword)
ORDER BY 2 DESC

But I will have to add the disclaimed that I have not tested the
above.

--
Erland Sommarskog, SQL Server MVP, esquel@.sommarskog.se

Books Online for SQL Server SP3 at
http://www.microsoft.com/sql/techin.../2000/books.asp|||>> I have a database where each row has a set of keywords separated by
commas <<

You are in violation of First Normal Form, so we are not even in a
relational model at the start of this.

>> a query where I find records [sic] that have a commonality of
keywords <<

CREATE TABLE Keywords
(title_id INTEGER NOT NULL,
keyword VARCHAR(15) NOT NULL,
PRIMARY KEY (title_id, keyword));

load this table with your search words:

CREATE TABLE Searchwords
(keyword VARCHAR(15) NOT NULL PRIMARY KEY);

now the query is easy.

SELECT K1.title_id, COUNT(*) AS matches
Keywords AS K1,
Searchwords AS S1
WHERE K1.keyword = S1.keyword
GROUP BY K1.title_id
ORDER BY matches DESC;

>>... and obviously the ones that match the most keywords should be
shown first.<<

Actually, ordering is a display issue for the front end and not the
database, but you can add an ORDER BY clause. Having said all of this,
have you considered using a text search tool instead of SQL? Cheap,
fast and much more powerful for this knd of thing.