|
Prev: Errors with linked server
Next: Week no query
From: ATS on 11 Feb 2005 14:05 PRB: Single Query to build database and schema. Please help, I'm quite frustrated with a problem. I want to issue a SINGLE query to completely build my database (IF IT DOESN'T ALREADY EXIST), "use" it, build an entire schema of tables, stored procedures, triggers, and even populate tables with data. Envision a typical ASP/ADO using program calling the query as such: ============================================ <%@ Language=JavaScript %> <% var Connection_Temp; var ResultSet_Temp; var csMY_QRY, csOPTION, csMY_DB_NAME; csMY_QRY = "~~~~~~~ What ever ~~~~~~~~"; csMY_QRY = csMY_QRY.replace("<%=DB%>", csMY_DB_NAME); csMY_QRY = csMY_QRY.replace("<%=OPTION%>", csOPTION); .. .. .. Connection_Temp = Server.CreateObject("ADODB.Connection"); Connection_Temp.ConnectionTimeout = 45; Connection_Temp.Open("DRIVER={SQL Server};SERVER=My_SVR;UID=MY_UID;PWD=MY_PWD"); ResultSet_Temp = Connection_Temp.Execute(csMY_QRY); %> <html> </html> ============================================ There are several "issues" which are making this very difficult to solve: 1) "CREATE DATABASE" and "USE" do not accept variables. 2) "USE" can not be used in a stored procedure or trigger. 3) sp_executesql only accepts NVARCHAR, NTEXT. 4) NVARCAHR can only be declared up to 4000 bytes. 5) NTEXT data types can only be declared as a parameter, not with "DECLARE". 6) NTEXT defined as parameters can not be assigned with SELECT statements. 7) A typical schema will surely require more than 4000 characters to be represented as a string. 8) Even tables with NTEXT can not be fetched into a NTEXT variable such as this: create table TEST(JUNK ntext, NAME nvarchar(50) primary key) insert into TEST(NAME, JUNK) values('ME', 'JUNK') create procedure TRY(ntext @csTRY) as begin select @csTRY = JUNK from TEST where NAME = 'ME' -- This fails... -- Can't assign the NTEXT. end 9) "GO" can not be used in a stored procedure" 10) "GO" can not be used in a single query passed to ADO as in the above example. Put another way, imagine setting csMY_QRY as such: csMY_QRY = "go \r\n exec sp_help \r\n go exec sp_help"; This will not work in the sample above. SQL Server will say [Microsoft][ODBC SQL Server Driver][SQL Server]The object 'go' does not exist in database 'master'. 11) Building the schema MUST be done with transaction handling, so that if one "CREATE TABLE" fails, they all roll back. 12) THIS HAS TO BE A QUERY. I am convinced that this can be done. It may require a LOT of sp_executesql calls, but I feel it can be done. Any ideas and/or help would be much appreciated. If nothing else, I would very much like for Microsoft to publish the final outcome of this PRB as a full blown MSDN article to help everyone. I've noticed here in the discussion groups that many people are trying to accomplish this, but are typically getting hung on "CREATE DATABASE" or "USE" limitations.
From: ATS on 11 Feb 2005 14:13 I have an update already. I believe that this WHOLE PRB can be solved if we can do one of the following: Use some sort of SP to select from a temporary table that has an NTEXT, to fetch a list of queries, where each query is then executed by something like sp_executesql, where if ANY failure occurs, the caller will know it, and then be able to roll that query back, and any previous query. The key is to somehow have an NTEXT variable to get the query, and then pass it to a sp_executesql as such: ~~~~ somehow DECALRE ~~~~~ @QRY ntext select * from QRY_TABLE_WITH_NTEXT_QUERIES ~~~ CURSOR: for each row returned, select into @QRY ~~~ exec sp_executesql @QRY ~~~ fetch next - do loop
From: ATS on 11 Feb 2005 15:47 Yet another update. I'm almost there. The NTEXT is the KEY issue. If ONLY I could programmatically create and populate an NTEXT variable, WITH data from a "select * from TABLE_WITH_NTEXT_COLUMN", then I'm sure this PRB would be solved. Here is a sample QRY I have made so far. It fails on the FETCH NEXT, where the error is "[Microsoft][ODBC SQL Server Driver][SQL Server]Cannot fetch into text, ntext, and image variables. " =============================== begin transaction set XACT_ABORT on set NOCOUNT on declare @csQRY nvarchar(4000) declare @CrLf nvarchar(5) declare @QQ nvarchar(5) select @CrLf = char(13) + char(10) select @QQ = char(39) + char(39) select @csQRY = 'create table QTs([NAME] nvarchar(50), [QRY] ntext)' exec sp_executesql @csQRY select @csQRY = 'insert into QTs([NAME], [QRY]) values(' + char(39) + 'QRY' + char(39) + ', ' + char(39) + 'create database MY_DB' + char(39) + ')' exec sp_executesql @csQRY select @csQRY = 'insert into QTs([NAME], [QRY]) values(' + char(39) + 'QRY' + char(39) + ', ' + char(39) + 'create table MY_DB.dbo.[FUN]([NAME] nvarchar(50))' + char(39) + ')' exec sp_executesql @csQRY select @csQRY = 'create procedure DO_QRY(@QRY ntext = ' + @QQ + ') as' + @CrLf + 'begin' + @CrLf + ' begin transaction' + @CrLf + ' declare TRY_CURSOR cursor for select [QRY] from QTs' + @CrLf + ' open TRY_CURSOR' + @CrLf + ' fetch next from TRY_CURSOR into @QRY' + @CrLf + ' while @@FETCH_STATUS = 0' + @CrLf + ' begin' + @CrLf + ' exec sp_executesql @QRY' + @CrLf + ' if (@@ERROR <> 0)' + @CrLf + ' begin' + @CrLf + ' rollback transaction' + @CrLf + ' return' + @CrLf + ' end' + @CrLf + ' fetch next from TRY_CURSOR into @QRY' + @CrLf + ' end' + @CrLf + ' commit transaction' + @CrLf + 'end' + @CrLf exec sp_executesql @csQRY select @csQRY = 'exec DO_QRY' exec sp_executesql @csQRY commit transaction
From: ATS on 11 Feb 2005 16:03 Back to being dead in the water. I replaced the NTEXT with NVARCHAR(3000), and tried the same login. It failed on the create database. Now what? begin transaction set XACT_ABORT on set NOCOUNT on declare @csQRY nvarchar(4000) declare @CrLf nvarchar(5) declare @QQ nvarchar(5) select @CrLf = char(13) + char(10) select @QQ = char(39) + char(39) select @csQRY = 'create table QTs([NAME] nvarchar(50), [QRY] nvarchar(3900))' exec sp_executesql @csQRY select @csQRY = 'insert into QTs([NAME], [QRY]) values(' + char(39) + 'QRY' + char(39) + ', ' + char(39) + 'create database MY_DB' + char(39) + ')' exec sp_executesql @csQRY select @csQRY = 'insert into QTs([NAME], [QRY]) values(' + char(39) + 'QRY' + char(39) + ', ' + char(39) + 'create table MY_DB.dbo.[FUN]([NAME] nvarchar(50))' + char(39) + ')' exec sp_executesql @csQRY select @csQRY = 'create procedure DO_QRY as' + @CrLf + 'begin' + @CrLf + ' begin transaction' + @CrLf + ' declare @QRY nvarchar(4000)' + @CrLf + ' declare TRY_CURSOR cursor for select [QRY] from QTs' + @CrLf + ' open TRY_CURSOR' + @CrLf + ' fetch next from TRY_CURSOR into @QRY' + @CrLf + ' while @@FETCH_STATUS = 0' + @CrLf + ' begin' + @CrLf + ' exec sp_executesql @QRY' + @CrLf + ' if (@@ERROR <> 0)' + @CrLf + ' begin' + @CrLf + ' rollback transaction' + @CrLf + ' return' + @CrLf + ' end' + @CrLf + ' fetch next from TRY_CURSOR into @QRY' + @CrLf + ' end' + @CrLf + ' commit transaction' + @CrLf + 'end' + @CrLf exec sp_executesql @csQRY select @csQRY = 'exec DO_QRY' exec sp_executesql @csQRY commit transaction ================================= In QA, the return is as such: ================================== Server: Msg 266, Level 16, State 2, Procedure DO_QRY, Line 14 Transaction count after EXECUTE indicates that a COMMIT or ROLLBACK TRANSACTION statement is missing. Previous count = 1, current count = 0. Server: Msg 266, Level 16, State 1, Line 1 Transaction count after EXECUTE indicates that a COMMIT or ROLLBACK TRANSACTION statement is missing. Previous count = 1, current count = 0. Server: Msg 226, Level 16, State 1, Line 1 CREATE DATABASE statement not allowed within multi-statement transaction. Server: Msg 3902, Level 16, State 1, Line 38 The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION. =============================== Any ideas?
From: ATS on 11 Feb 2005 16:41 SOLVED!!!!!! The CREATE DATABASE can be issued. I just had to commit any TX that may have existed before the CREATE DATABASE for it to work. Then I could resume another "BEGIN TRANSACTION" and continue on. I also needed to use a WHILE-LOOP to be sure to commit all transactions that may be created by the various CREATE TABLEs I would execute. But I did get it to work. Final sample below: ============ This should be published into MSDN, no fooling! ======================================= begin transaction set XACT_ABORT on set NOCOUNT on declare @csQRY nvarchar(4000) declare @CrLf nvarchar(5) declare @QQ nvarchar(5) select @CrLf = char(13) + char(10) select @QQ = char(39) + char(39) select @csQRY = 'create database OptiDoc_3X' commit transaction exec sp_executesql @csQRY begin transaction select @csQRY = 'create table QTs([NAME] nvarchar(50), [QRY] nvarchar(3900))' exec sp_executesql @csQRY --select @csQRY = 'insert into QTs([NAME], [QRY]) values(' + char(39) + 'QRY' + char(39) + ', ' + char(39) + 'create database MY_DB' + char(39) + ')' select @csQRY = 'insert into QTs([NAME], [QRY]) values(' + char(39) + 'QRY' + char(39) + ', ' + char(39) + 'create table MY_DB..MY_TBL([NAME] nvarchar(50))' + char(39) + ')' exec sp_executesql @csQRY begin transaction select @csQRY = 'create procedure DO_QRY as' + @CrLf + 'begin' + @CrLf + ' begin transaction' + @CrLf + ' declare @QRY nvarchar(4000)' + @CrLf + ' declare TRY_CURSOR cursor for select [QRY] from QTs' + @CrLf + ' open TRY_CURSOR' + @CrLf + ' fetch next from TRY_CURSOR into @QRY' + @CrLf + ' while @@FETCH_STATUS = 0' + @CrLf + ' begin' + @CrLf + ' select @QRY' + @CrLf + ' exec sp_executesql @QRY' + @CrLf + ' if (@@ERROR <> 0)' + @CrLf + ' begin' + @CrLf + ' select ' + @QQ + '-- Error!!!' + @QQ + @CrLf + ' rollback transaction' + @CrLf + ' return' + @CrLf + ' end' + @CrLf + ' fetch next from TRY_CURSOR into @QRY' + @CrLf + ' end' + @CrLf + ' close TRY_CURSOR' + @CrLf + ' deallocate TRY_CURSOR' + @CrLf + ' commit transaction' + @CrLf + 'end' + @CrLf exec sp_executesql @csQRY select @csQRY = 'exec DO_QRY' exec sp_executesql @csQRY select @csQRY = 'drop procedure DO_QRY' exec sp_executesql @csQRY select @csQRY = 'drop table QTs' exec sp_executesql @csQRY while @@TRANCOUNT > 0 begin commit transaction end
|
Pages: 1 Prev: Errors with linked server Next: Week no query |