I'm trying to rebuild a database from a text file, using VBA. To insert the ID values, I call this before sending in the INSERTs:
SET IDENTITY_INSERT TableName ON
This seems to work fine for most TableNames, but when I call it on table 'Accounts' I get an interesting error:
"IDENTITY_INSERT is already ON for table 'test.dbo.PropertyAssets'. Cannot perform SET operation for table 'Accounts'."
I'm guessing this has to do with fkey constraints or such, but does anyone know for sure?
You can only set IDENTITY_INSERT on for one table at a time in your session. If you want to use it on multiple tables, you need to set it ON and OFF consistently, see the template below:
SET IDENTITY_INSERT TableName ON
--insert values with IDs
SET IDENTITY_INSERT TableName OFF
SET IDENTITY_INSERT PropertyAssets ON
--insert value with IDs
SET IDENTITY_INSERT PropertyAssets OFF
You just need another session. I simply reconnected to the same database and it run without any issues.
Of course I changed the script to set IDENTITY_INSERT to OFF in the end.
I have a stored procedure which is returning a result in an xml #Data output parameter
To assign data in xml code is
SELECT #data= (
SELECT DISTINCT
CONVERT(varchar(2),u.USER_SOURCE ) + '~' +
CONVERT(varchar(20), u.[USER_ID]) + '-' +
CONVERT(varchar(10), u.DEALER_ID) as USER_DEALER_ID
FROM #users u FOR XML RAW('users'))
When I exec the procedure in SQL Server Mgmt Studio, I can see the result OK.
This procedure is been called from another procedure, and that parent procedure is used in SSRS.
In SSRS I am getting error
Query execution failed for dataset 'DataSet1'. Invalid column name
'USER_SOURCE'. Invalid column name 'USER_ID'. Invalid column name
'DEALER_ID'.
Could you please help?
Thanks,
Chetan
Here's a script which I think reproduces a problem identical to yours:
CREATE PROCEDURE TestTmpTable
#value varchar(20)
AS
BEGIN
CREATE TABLE #test (id int IDENTITY, value varchar(20));
INSERT INTO #test (value) VALUES (#value)
SELECT * FROM #test;
DROP TABLE #test;
END
GO
CREATE TABLE #test (id int IDENTITY, value2 varchar(20));
EXEC TestTmpTable 'some text';
SELECT * FROM #test;
DROP TABLE #test;
GO
DROP PROCEDURE TestTmpTable
As you can see, there are two #test tables here, one is created in the stored procedure, the other one in the batch that invokes the stored procedure. They have different structures: one has a column named value, the other a column named value2. If you run the script, you'll see this error:
Msg 207, Level 16, State 1, Procedure TestTmpTable, Line 6
Invalid column name 'value'.
I can't point you to a relevant documentation article at the moment, but to me it is evident enough that some preliminary name checking is taking place immediately before the execution of the SP. At that stage, a discrepancy between the column names referenced in the stored procedure and those actually present in the already existing table is revealed, which renders the execution impossible.
If you change value2 to value, the script will work without any problem, and there will be two row sets in the output, one with the 'some text' value, the other empty. And of course the script will work if you remove all parts related to the external #test table.
So, check the places where your procedure is called to see if any other #users table can be existing by that moment, and if so, amend the issue according to your situation.
The code is like this
INSERT INTO TABLE (VAL1,VAL2,VAL3) VALUES (X,Y,Z)
GetLastInsertID #tablename='TABLE'
GetLastInsertID is this Stored Procedure:
SELECT ##IDENTITY AS LastID FROM TABLE
How do I get the stored procedure to return the 'LastID' as requested in the Select ##IDENTITY statement above?
I get the following error:
Incorrect syntax near 'GetLastInsertId'.
...but this works fine when executed by itself:
GetLastInsertID #tablename='TABLE'
Okay, thanks i updated it to Scope_Identity(). But you're saying not to put it in a different SP, to put it in the same SP as the Insert?
Again, i still am getting an error when i combine an insert with this:
SELECT SCOPE_IDENTITY() AS LastID FROM TABLE
Here is the new error message:
There is already an object named 'TABLE' in the database.
It's a bad idea to separate this into a stored procedure at all, because a stored procedure creates a new scope/context. That leaves you open to grabbing the wrong ID number. If one user in a session inserts many rows together, you might get the wrong result.
Instead, you almost always want the scope_identity() function, and you want to call it in the same context as the statement that created the new record.
In the first place you do not ever want to use ##identity as it can break if someone adds a trigger.
What you want to use is the OUTPUT clause or scope_identity. See Books online for examples of how to use OUTPUT.
your error is in your failure to include the EXECUTE command, try this:
INSERT INTO TABLE (VAL1,VAL2,VAL3) VALUES (X,Y,Z)
EXEC GetLastInsertID #tablename='TABLE'
the EXEC is assumed when you attempt to run a procedure with no other commands, however when you include the INSERT it makes the EXEC required.
Now, you really need to determine if what you are trying to do is a good design.
try this:
DECLARE #LastId int
INSERT INTO TABLE (VAL1,VAL2,VAL3) VALUES (X,Y,Z)
SELECT #LastID=SCOPE_IDENTITY()
Here is my sample code that does this. (But the stored proc doesn't add any value.)
--First create a test table.
create table test
(id int identity,
name varchar(30))
go
--A stored proc that returns the scope_identity()
create proc dbo.spTest
as
insert into test(name)
values ('test')
return scope_identity()
go
-- Sample call
declare #newId int
exec #newId = spTest
print #newId
I have query in a stored procedure that calls some linked servers with some dynamic SQL. I understand that EF doesn't like that, so I specifically listed all the columns that would be returned. Yet, it still doesn't like that. What am I doing wrong here? I just want EF to be able to detect the columns returned from the stored procedure so I can create the classes I need.
Please see the following code that makes up the last lines of my stored procedure:
SELECT
#TempMain.ID,
#TempMain.Class_Data,
#TempMain.Web_Store_Class1,
#TempMain.Web_Store_Class2,
#TempMain.Web_Store_Status,
#TempMain.Cur_1pc_Cat51_Price,
#TempMain.Cur_1pc_Cat52_Price,
#TempMain.Cur_1pc_Cat61_Price,
#TempMain.Cur_1pc_Cat62_Price,
#TempMain.Cur_1pc_Cat63_Price,
#TempMain.Flat_Length,
#TempMain.Flat_Width,
#TempMain.Item_Height,
#TempMain.Item_Weight,
#TempMain.Um,
#TempMain.Lead_Time_Code,
#TempMain.Wp_Image_Nme,
#TempMain.Wp_Mod_Dte,
#TempMain.Catalog_Price_Chg_Dt,
#TempMain.Description,
#TempMain.Supersede_Ctl,
#TempMain.Supersede_Pn,
TempDesc.Cust_Desc,
TempMfgr.Mfgr_Item_Nbr,
TempMfgr.Mfgr_Name,
TempMfgr.Vendor_ID
FROM
#TempMain
LEFT JOIN TempDesc ON #TempMain.ID = TempDesc.ID
LEFT JOIN TempMfgr ON #TempMain.ID = TempMfgr.ID
EF doesn't support importing stored procedures which build result set from:
Dynamic queries
Temporary tables
The reason is that to import the procedure EF must execute it. Such operation can be dangerous because it can trigger some changes in the database. Because of that EF uses special SQL command before it executes the stored procedure:
SET FMTONLY ON
By executing this command stored procedure will return only "metadata" about columns in its result set and it will not execute its logic. But because the logic wasn't executed there is no temporary table (or built dynamic query) so metadata contains nothing.
You have two choices (except the one which requires re-writing your stored procedure to not use these features):
Define the returned complex type manually (I guess it should work)
Use a hack and just for adding the stored procedure put at its beginning SET FMTONLY OFF. This will allow rest of your SP's code to execute in normal way. Just make sure that your SP doesn't modify any data because these modifications will be executed during import! After successful import remove that hack.
Adding this Non-Logical block of code solved the problem. Even though it will never Hit
IF 1=0 BEGIN
SET FMTONLY OFF
END
Why does my typed dataset not like temporary tables?
http://social.msdn.microsoft.com/Forums/en-US/adodotnetdataset/thread/fe76d511-64a8-436d-9c16-6d09ecf436ea/
Or you can create a User-Defined Table Type and return that.
CREATE TYPE T1 AS TABLE
( ID bigint NOT NULL
,Field1 varchar(max) COLLATE Latin1_General_CI_AI NOT NULL
,Field2 bit NOT NULL
,Field3 varchar(500) NOT NULL
);
GO
Then in the procedure:
DECLARE #tempTable dbo.T1
INSERT #tempTable (ID, Field1, Field2, Field3)
SELECT .....
....
SELECT * FROM #tempTable
Now EF should be able to recognize the returned columns type.
As some others have noted, make sure the procedure actually runs. In particular, in my case, I was running the procedure happily without error in SQL Server Management Studio completely forgetting that I was logged in with admin rights. As soon as I tried running the procedure using my application's principal user I found there was a table in the query that that user did not have permission to access.
Interesting side note: Had the same problem which I first solved by using Table Variables, rather than Temp Tables (just for the import). That wasn't particularly intuitive to me, and threw me off when initially observing my two SProcs: one using Temp tables and one with Table Variables.
(SET FMTONLY OFF never worked for me, so I just changed my SProcs temporarily to get the column info, rather than bothering with the hack on the EF side just as an FYI.)
My best option was really just manually creating the complex type and mapping the function import to it. Worked great, and the only difference ended up being that an additional FactoryMethod to create the properties was included in the Designer.
What I would add is:
That the import also fails if the stored procedures has parameters and returns no result set for the default parameter values.
My stored procedure had 2 float parameters and would not return anything when both parameters are 0.
So in order to add this stored procedure to the entity model, I set the value of these parameters in the stored procedure so that it is guaranteed to return some rows, no matter what the parameters actually are.
Then after adding this stored procedure to the entity model I undid the changes.
both solutions :
1- Define the returned complex type manually (I guess it should work)
2- Use a hack and just for adding the stored procedure put at its beginning SET FMTONLY OFF.
not working with me in some procedure however it worked with other one!
my procedure ends with this line:
SELECT machineId, production [AProduction]
, (select production FROM #ShiftBFinalProd WHERE machineId = #ShiftAFinalProd.machineId) [BProduction]
, (select production FROM #ShiftCFinalProd WHERE machineId = #ShiftAFinalProd.machineId) [CProduction]
FROM #ShiftAFinalProd
ORDER BY machineId
Thanks
In addition to what #tmanthley said, be sure that your stored procedure actually works by running it first in SSMS. I had imported some stored procedures and forgot about a couple dependent scalar functions, which caused EF to determine that the procedure returned no columns. Seems like a mistake I should have caught earlier on, but EF doesn't give you an error message in that case.
Entity Framework will try to get the columns by executing your stored procedure, passing NULL for every argument.
Please make sure that the stored procedure will return something under all the circumstances. Note it may have been smarter for Entity Framework to execute the stored proc with default values for the arguments, as opposed to NULLs.
ER does the following to get the metadata of the table:
SET FMTONLY ON
This will break your stored procedure in various circumstances, in particular, if it uses a temporary table.
So to get a result as complex type; please try by adding
SET FMTONLY OFF;
This worked for me - hope it works for you too.
Referred from https://social.msdn.microsoft.com/Forums/en-US/e7f598a2-6827-4b27-a09d-aefe733b48e6/entity-model-add-function-import-stored-procedure-returns-no-columns?forum=adodotnetentityframework
In my case adding SET NOCOUNT ON; at the top of the procedure fixed the problem. It's best practice anyway.
In my case SET FMTONLY OFF did not work. The method I followed is, I took backup of original stored procedure and replace with only column name like the below query.
Select Convert(max,'') as Id,Convert(max,'') as Name
After this change, create new function import, complex type in entity framework.
Once the function import and complex type is created, replace the above query with your original stored procedure.
SET FMTONLY OFF
worked for me for one of the procedure but failed for other procedure. Following steps helps me to resolve my problem
Within a stored procedure, I have created temporary table with the same column type and inserted all the data returned by dynamic query to temp table.
and selected the temp table data.
Create table #temp
(
-- columns with same types as dynamic query
)
EXEC sp_executeSQL #sql
insert into #temp
Select * from #temp
drop table #temp
Deleted existing complex type, import function and stored procedure instance for old stored procedure and updated entity model for current new procedure.
Edit the imported Function in entity modal for desired complex type, you will get all the column information there which is not getting for previous stored procedure.
once you have done with the type creation you can delete the temporary table from stored procedure and then refresh Entity Framework.
In Entity framework, while getting column information the sql executes the procedure with passing null values in parameter. So I handled null case differently by creating a temp table with all the required columns and returning all the columns with no value when null is passed to the procedure.
In my procedure there was dynamic query, something like
declare #category_id int
set #category_id = (SELECT CATEGORY_ID FROM CORE_USER where USER_ID = #USER_ID)
declare #tableName varchar(15)
declare #sql VARCHAR(max)
declare #USER_IDT varchar(100)
declare #SESSION_IDT varchar(10)
IF (#category_id = 3)
set #tableName = 'STUD_STUDENT'
else if(#category_id = 4)
set #tableName = 'STUD_GUARDIAN'
if isnull(#tableName,'')<>''
begin
set #sql = 'SELECT [USER_ID], [FIRST_NAME], SCHOOL_NAME, SOCIETY_NAME, SCHOOL_ID,
SESSION_ID, [START_DATE], [END_DATE]
from #tableName
....
EXECUTE (#sql)
END
ELSE
BEGIN
SELECT * from #UserPrfTemp
END
I was not getting the column information in
my case after using the set FMTONLY OFF trick.
This is temp table I created to get the blank data.
Now I am getting the column info
Create table #UserPrfTemp
(
[USER_ID] bigint,
[FIRST_NAME] nvarchar(60),
SCHOOL_NAME nvarchar(60),
SOCIETY_NAME nvarchar(200)
.....
}
I solved this problem creating a table variable and then returning from it.
DECLARE #VarTable TABLE (
NeededColumn1 VARCHAR(100),
NeededColumn2 INT,
NeededColumn3 VARCHAR(100)
)
...
--Fetch Data from Linked server here
...
INSERT INTO #VarTable (NeededColumn1,NeededColumn2,NeededColumn3)
SELECT Column1, Column2, Column3
FROM #TempTable
SELECT * FROM #VarTable.
In that manner, your the SP result will be bounded to the table variable, which EF has access to.
I discovered a method that should help most people out whatever's happening.
Pull up your favourite SQL client and run the proc that you're trying to update with every parameter = null. Visual Studio is literally trying to do this when SET FMTONLY ON. Run a trace. You'll see.
You'll probably get an error, or unexpected data out. Fix that and your issue is fixed.
In my case the function read in JSON and failed because the JSON string was empty.
I just put something like
IF(#FooJSON IS NULL)
BEGIN
SELECT 1 VAR1, 2 VAR2;
END
ELSE
--OTHER LOGIC
That's probably an ugly solution, but I inherited this mess and we don't go into Ravenholm.
Change #Temp tables with WITH SQL EXPRESSION
We have two columns in a database which is currently of type varchar(16). Thing is, it contains numbers and always will contain numbers. We therefore want to change its type to integer. But the problem is that it of course already contains data.
Is there any way we can change the type of that column from varchar to int, and not lose all those numbers that are already in there? Hopefully some sort of sql we can just run, without having to create temporary columns and create a C# program or something to do the conversion and so forth... I imagine it could be pretty easy if SQL Server have some function for converting strings to numbers, but I am very unstable on SQL. Pretty much only work with C# and access the database through LINQ to SQL.
Note: Yes, making the column a varchar in the first place was not a very good idea, but that is unfortunately the way they did it.
The only reliable way to do this will be using a temporary table, but it will not be much SQL:
select * into #tmp from bad_table
truncate table bad_table
alter bad_table alter column silly_column int
insert bad_table
select cast(silly_column as int), other_columns
from #tmp
drop table #tmp
The easiest way to do this is:
alter table myTable alter column vColumn int;
This will work as long as
all of the data will fit inside an int
all of the data can be converted to int (i.e. a value of "car" will fail)
there are no indexes that include vColumn. If there are indexes, you will need to include a drop and create for them to get back to where you were.
Just change the datatype in SQL Server Management Studio.
(You may need to go to menu Tools → Options → Designers, and disable the option that prevents saving changes that re-create the table.)
I totally appreciate the previous answers, but also thought a more complete answer would be helpful to other searchers...
There are a couple caveats that would be helpful if you making the changes on a production type table.
If you have an identity column defined on the table you will have to set IDENTITY_INSERT on and off around the re-insert of data. You will also have to use an explicit column list.
If you want to be sure of not killing data in the database, use TRANSACTIONS around the truncate/alter/reinsert process
If you have a lot of data, then trying to just make the change in SQ Server Management Studio could fail with a timeout and you could lose data.
To expand the answer that #cjk gave, look at the following:
Note: 'tuc' is just a placeholder in this script for the real tablename
begin try
begin transaction
print 'Selecting Data...'
select * into #tmp_tuc from tuc
print 'Truncating Table...'
truncate table tuc
alter table tuc alter column {someColumnName} {someDataType} [not null]
... Repeat above until done
print 'Reinserting data...'
set identity_insert tuc on
insert tuc (
<Explicit column list (all columns in table)>
)
select
<Explicit column list (all columns in table - same order as above)>
from #tmp_tuc
set identity_insert tuc off
drop table #tmp_tuc
commit
print 'Successful!'
end try
begin catch
print 'Error - Rollback'
if ##trancount > 0
rollback
declare #ErrMsg nvarchar(4000), #ErrSeverity int
select #ErrMsg = ERROR_MESSAGE(), #ErrSeverity = ERROR_SEVERITY()
set identity_insert tuc off
RAISERROR(#ErrMsg, #ErrSeverity, 1)
end catch