Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 General SQL Server Forums
 New to SQL Server Programming
 Looping through dataset

Author  Topic 

RWSmith
Starting Member

4 Posts

Posted - 2011-08-08 : 13:12:16
Okay, I am new.
Using .NET 2.0 and SQL Server 2005, this may actually be more of a vb question than a sql question, not sure. My problem is working with the dataset.
I have a vb.net function that needs to find any unit id from a unit table associated with a building. Need to grab top unit id from dataset, delete all other unit ids in that table and use top unit id to set all other records in four different tables to the top unit id. I may be going about this all wrong. Any help or suggestions would be appreciated.
So far it looks like this....

Protected Sub GetAssociatedUnits()
Dim sql As String
sql = "" & _
"SELECT Units.UnitID FROM Units WHERE BuildingID = '" & _buildingID & "') "
Dim dataSet As New DataSet
If (Database.GetDataSet(sql, dataSet) = False)
Me.Error_Label.Text += Database.DbError & "<br>"
Return
End If
Dim rowCount As Integer
rowCount = dataSet.Tables(0).Rows.Count
If (rowCount > 1)
_tempUnitID = Convert.ToInt32("SELECT TOP UnitID FROM Units WHERE BuildingID = '" & _buildingID & "') " )

'loop through result set and update any other tables with that unit id then delete all but top unit id from unit table

FOR Each row As DataRow In dataSet.Tables(0).Rows
_tempUnitID1 = CType(dataSet.Tables(0).Rows.Item("UnitID"),Int32)
"UPDATE Meetings Set UnitID = '" & _tempUnitID & "' WHERE UnitID = '" & _tempUnitID1 & "')" & _
"UPDATE DocumentAssociations Set UnitID = '" & _tempUnitID & "' WHERE UnitID = '" & _tempUnitID1 & "') " & _
"UPDATE UnitProducts Set UnitID = '" & _tempUnitID & "' WHERE UnitID = '" & _tempUnitID1 & "') " & _
"UPDATE UnitContacts Set UnitID = '" & _tempUnitID & "' WHERE UnitID = '" & _tempUnitID1 & "') "
"DELETE * FROM Units WHERE UnitID = '" &_tempUnitID1 & "') "


NEXT

End If
End Sub

sunitabeck
Master Smack Fu Yak Hacker

5155 Posts

Posted - 2011-08-08 : 15:44:21
It is much safer and easier to do this in a stored procedure.

It is safer because you can ensure the atomicity of the operations (i.e., either all of the operations will succeed together, or they will all fail together, thus ensuring data integrity). It is also safer because it avoids the "ad-hoc" query which can be less efficient, may even be prone to SQL injection attacks.

Easier because, as you can see, there are fewer lines of code, and it looks more readable (at least to me )

I don't completely understand your business logic, or I may have misunderstood them. So this is only and example, please look through it and understand and modify to your requirements, and test in a dev environment if you do choose to use this approach.

Once you have the stored proc, in .Net 2.0, you can connect to the database using ADO.Net; you would pass in one parameter to the stored proc, namely the building id.
CREATE PROCEDURE dbo.FixupUnitIds
@building_id INT
AS

BEGIN TRY -- exception handling.
BEGIN TRAN -- do it in a transaction, so all of the operations will succeed or fail together.

DECLARE @highest_unit_id INT;
-- find the highest unit id
SELECT @highest_unit_id = MAX(UnitId) FROM Units WHERE BuildingId = @building_id;

-- update the four tables
UPDATE Meetings SET UnitID = @highest_unit_id WHERE BuildingId = @building_id;
UPDATE DocumentAssociations SET UnitID = @highest_unit_id WHERE BuildingId = @building_id;
UPDATE UnitProducts SET UnitID = @highest_unit_id WHERE BuildingId = @building_id;
UPDATE UnitContacts SET UnitID = @highest_unit_id WHERE BuildingId = @building_id;

-- delete all except the highest unit id
DELETE FROM Units WHERE UnitId <> @highest_unit_id AND BuildingId = @building_id;

COMMIT TRAN
END TRY
BEGIN CATCH
ROLLBACK TRAN;
SELECT
ERROR_NUMBER() AS ErrorNumber,
ERROR_SEVERITY() AS ErrorSeverity,
ERROR_STATE() AS ErrorState,
ERROR_PROCEDURE() AS ErrorProcedure,
ERROR_LINE() AS ErrorLine,
ERROR_MESSAGE() AS ErrorMessage
END CATCH

GO
Go to Top of Page

jcelko
Esteemed SQL Purist

547 Posts

Posted - 2011-08-08 : 23:49:19
Every SQL forum or newsgroup expects that you will post DDL, sample data and clear specifications which might might include output. This is explained in the FAQ section. We can not read minds; what would we need to know to do your job for you?

Tables must have keys and should have DRI, constraints, and all the basic features of a schema. You should know use ISO-8601 Standards for temporal data, avoid needless dialect, basic data modeling and use ISO-11179 Standards for data element names. Please tell us if you can change the DDL.

>> I have a vb.net function that needs to find any unit id from a unit table associated with a building. Need to grab top unit id from dataset, delete all other unit ids in that table and use top unit id to SET all other records [aic: rows are not records] in four different tables to the top unit id. I may be going about this all wrong <<

Yes, this all wrong. SQL is a SET-oriented language. Writing a loop is like cannibalism to SQL programmers; you might do it at home, but not where people can see you.

You are writing a “scratch tape” as if you were still in COBOL or Flow-matic with magnetic tape files. The same unit_nbr physically repeated in so many places is a sign of more “mag tape in SQL” thinking. Since you violated basic Netiquette we have no way of re-writing the DDL for you. Let me do your job:

CREATE TABLE Units
(bldg_nbr VARCHAR(5) NOT NULL,
unit_nbr VARCHAR(5) NOT NULL,
PRIMARY KEY (bldg_nbr, unit_nbr_max),
..);

You can find the set of max units and put it in a VIEW; the VIEW is always current.

CREATE VIEW Bldg_Unit_Max(bldg_nbr, unit_nbr_max)
AS
SELECT bldg_nbr, MAX(unit_nbr) AS unit_nbr_max
FROM Units
GROUP BY bldg_nbr;

Assume each of these other tables has a building number that matches to the VIEW, we can write a colleciton of VIEWs

CREATE VIEW Meetings_Unit_Max (..)
AS
SELECT M.*, MAX(U.unit_nbr) AS unit_nbr_max
FROM Meetings AS M, Units AS U;

The VIEWs will always be current. But if you insist on a mag tape file, you can use a VIEW to update your other tables.

BEGIN
UPDATE Meetings
SET unit_nbr
= (SELECT unit_nbr_max
FROM Bldg_Unit_Max AS BUM
WHERE BUM.bldg_nbr = Meetings.bldg_nbr);

UPDATE DocumentAssociation
SET unit_nbr
= (SELECT unit_nbr_max
FROM Bldg_Unit_Max AS BUM
WHERE BUM.bldg_nbr = DocumentAssociation.bldg_nbr);

UPDATE UnitProducts
SET unit_nbr
= (SELECT unit_nbr_max
FROM Bldg_Unit_Max AS BUM
WHERE BUM.bldg_nbr = UnitProducts.bldg_nbr);

UPDATE UnitContacts
SET unit_nbr
= (SELECT unit_nbr_max
FROM Bldg_Unit_Max AS BUM
WHERE BUM.bldg_nbr = UnitContacts.bldg_nbr);
END;



--CELKO--
Books in Celko Series for Morgan-Kaufmann Publishing
Analytics and OLAP in SQL
Data and Databases: Concepts in Practice
Data, Measurements and Standards in SQL
SQL for Smarties
SQL Programming Style
SQL Puzzles and Answers
Thinking in Sets
Trees and Hierarchies in SQL
Go to Top of Page

RWSmith
Starting Member

4 Posts

Posted - 2011-08-09 : 14:42:51
Apologies I did not practice proper netiquette! Sorry, 60 year old man here, so facing a learning curve.
sunitabeck Thank you so much for your suggestion of a stored procedure. I had not thought of that.
jcelko, thanks for you help as well, you obviously know your stuff.
Yes each table has a primary key and no building id is only in the unit table. This is me trying to fix an old .NET 2.0 application that is
having issues with users wanting to do things the application was not originally designed to do. So, to better explain my issue, users often create buildings
as mutli-family buildings and add in multiple units before realizing that the building is a single family house. They then want it to magically
convert to a single family building with only one unit. So I am trying to behind the scenes take all of the existing units and any associated
documents and roll them all up under one unit. The loop was my idea to try to get all of the possible units with the building id and then grab the
top or max one and then use that id to update the other unit ids in the other corresponding tables. There can be up to several hundred unit ids for
the building in the units table. Thus the loop. Problem is the code needs to go through units one by one and grab any documents or meetings and then
update those records with the one unit id(max).
The other tables- meetings, documents and unit contacts each have a unitid field and primary keys of meetingid, documentid and contactid, respectively.
If this helps anyone understand my problem better, please offer suggestions. I will attempt to write this in a stored procedure utilizing the view idea jcelko
offered rather than looping through an array of unit id results and see what happens. Running out to buy a SQL book, maybe that will help, since I am in way
over my head.
Thanks again for your help, patience and suggestions.
Go to Top of Page

RWSmith
Starting Member

4 Posts

Posted - 2011-08-10 : 14:22:52
Okay, with your suggestions and code (thank you)I have created a stored procedure but when I parse to check the code I am getting lots of error messages I am not understanding. I changed some requirements since the most important piece is the documents associated with the unit. Here is what I have so far...
CREATE PROCEDURE dbo.sp_ConvertMFtoSF
@bldg_id INT
AS
BEGIN TRY
BEGIN TRAN
CREATE VIEW dbo.UnitBuildingView
AS
SELECT UnitID, BuildingID
FROM dbo.Units
WHERE BuildingID = @bldg_id
-- GO

DECLARE @first_unit_id INT;
-- find the oldest unit id
SELECT @first_unit_id = MIN(UnitId) FROM UnitBuildingView;

-- update the tables
UPDATE [dbo].[DocumentAssociations] SET UnitID = @first_unit_id WHERE BuildingId = @bldg_id;
UPDATE [dbo].[Buildings] SET BuildingUseType = 'SingleFamily', NumberUniits = '1' WHERE BuildingId = @bldg_id;

-- delete all except the highest unit id
DELETE FROM [dbo].[Units] WHERE UnitId <> @first_unit_id AND BuildingId = @bldg_id;

COMMIT TRAN
END TRY
-- BEGIN CATCH
-- ROLLBACK TRAN;
-- SELECT
-- ERROR_NUMBER() AS ErrorNumber,
-- ERROR_SEVERITY() AS ErrorSeverity,
-- ERROR_STATE() AS ErrorState,
-- ERROR_PROCEDURE() AS ErrorProcedure,
-- ERROR_LINE() AS ErrorLine,
-- ERROR_MESSAGE() AS ErrorMessage
-- END CATCH

GO



these are the error messages....

Msg 156, Level 15, State 1, Procedure sp_ConvertMFtoSF, Line 11
Incorrect syntax near the keyword 'VIEW'.
Msg 102, Level 15, State 1, Procedure sp_ConvertMFtoSF, Line 30
Incorrect syntax near 'TRY'.



The syntax near view and try?
I have searched through a SQL book I purchased and have looked at other stored procedures with views online and do not see the syntax error.
Did I need to move the view to be above the transaction start?
Any suggestions are greatly appreciated.
Thanks again for all of your help!!
Go to Top of Page

sunitabeck
Master Smack Fu Yak Hacker

5155 Posts

Posted - 2011-08-10 : 15:43:11
Change it like shown below. I think you may have copied code which somehow included a view definition nested inside your stored procedure definition. Run it in a test environment before you do anything for real.

Once you create the stored procedure using this code, run it like this:
exec dbo.sp_ConvertMFtoSF 3422 -- assuming 3422 is the building id.

If it does not do exactly what you need and you want to make changes, you can alter the stored procedure or drop and recreate it. You can drop a stored procedure using "DROP PROCEDURE dbo.sp_ConvertMFtoSF".

Here is the revised version of the stored proc.
CREATE PROCEDURE dbo.sp_ConvertMFtoSF
@bldg_id INT
AS
BEGIN TRY
BEGIN TRAN

SELECT UnitID, BuildingID
FROM dbo.Units
WHERE BuildingID = @bldg_id
-- GO

DECLARE @first_unit_id INT;
-- find the oldest unit id
SELECT @first_unit_id = MIN(UnitId) FROM UnitBuildingView;

-- update the tables
UPDATE [dbo].[DocumentAssociations] SET UnitID = @first_unit_id WHERE BuildingId = @bldg_id;
UPDATE [dbo].[Buildings] SET BuildingUseType = 'SingleFamily', NumberUniits = '1' WHERE BuildingId = @bldg_id;

-- delete all except the highest unit id
DELETE FROM [dbo].[Units] WHERE UnitId <> @first_unit_id AND BuildingId = @bldg_id;

COMMIT TRAN
END TRY
BEGIN CATCH
ROLLBACK TRAN;
SELECT
ERROR_NUMBER() AS ErrorNumber,
ERROR_SEVERITY() AS ErrorSeverity,
ERROR_STATE() AS ErrorState,
ERROR_PROCEDURE() AS ErrorProcedure,
ERROR_LINE() AS ErrorLine,
ERROR_MESSAGE() AS ErrorMessage
END CATCH

GO
Go to Top of Page

RWSmith
Starting Member

4 Posts

Posted - 2011-08-10 : 17:10:37
Sunitabeck,
Thank you so much for your help!! Unlike Mr.Celko with all his books to sell, you seem to be just trying to help people. Kudos to you and I pray many blessings come your way.
I was creating the view as Mr.Celko suggested in the stored procedure to hold the data in while I worked with it. But after reading your post I had a brainstorm and made separate calls. One to create the UnitBuildingView on the fly, then a modified version of the stored procedure, then a third call to drop the view. Works great!!
And for Mr.Celko, obviously I said I was new. Just began learning SQL this week to fix an issue for my small one man shop property renovation business, still have no idea what a DDL is? ISO-8601 Standards? What the hell is that? Do my job for me? You are a gem! Why even post a reply in the new to sql section if you have such an attitude about it? Your rudeness will come back to you one day sir. I pray that the universe blesses you anyway!
Sunitabeck Thanks again!!
Go to Top of Page

sunitabeck
Master Smack Fu Yak Hacker

5155 Posts

Posted - 2011-08-11 : 09:28:37
Creating a view on the fly for a one-time use and dropping it after the use is not a usual practice - Because creating the views and dropping them are expensive operations; Also views are sort of like tables (they are virtual tables) which, once created is available for you to use any time, just like tables.

Even though creating and dropping the views each time makes me a little queasy, if your code is working as you want it to I guess it is okay to leave well-enough alone. But, if you have performance issues or if it is not doing the tasks as you expect, post the scripts for the stored procedure and the views. (In object explorer in SQL Server Management studio you can right click on the stored proc or table and select script as -> Create to -> New Query editor window to script the stored proc/view).
Go to Top of Page
   

- Advertisement -