Invalid object name 'CHANGETABLE' - sql-server

I just enabled change tracking by turning on ALLOW_SNAPSHOT_ISOLATION, executing this query to turn on change tracking for the database
ALTER DATABASE [DatabaseName]
SET CHANGE_TRACKING = ON (CHANGE_RETENTION = 2 DAYS,AUTO_CLEANUP = ON)
and by finally enabling it on the table
ALTER TABLE [TableName]
ENABLE CHANGE_TRACKING WITH (TRACK_COLUMNS_UPDATED = OFF)
Now when I call
SELECT *
FROM CHANGETABLE(CHANGES, 0)
I get this error message:
Invalid object name 'CHANGETABLE'.
The database version is SQL Server 2012. How can CHANGETABLE be invalid and how can I make it work? I assumed it would work out of the box because it's a system function. It's even highlighted in SQL Server Management Studio. I modified a little bit of data between turning on change tracking and calling CHANGETABLE().

The correct syntax is
SELECT * FROM CHANGETABLE(CHANGES MyTableName,#last_version) as SomeAlias
This is shown in the documentation examples :
DECLARE #last_sync_version bigint;
SET #last_sync_version = <value obtained from query>;
SELECT [Emp ID], SSN,
SYS_CHANGE_VERSION, SYS_CHANGE_OPERATION,
SYS_CHANGE_COLUMNS, SYS_CHANGE_CONTEXT
FROM CHANGETABLE (CHANGES Employees, #last_sync_version) AS C;
Forgetting the table name results in Invalid object name 'CHANGETABLE'
Forgetting the table alias results in A table returned by the CHANGETABLE function must be aliased.

Related

SQL Server 2019 infinitely recompiles inline table valued function that does full text search with Parameterization = Forced

I have hit a problem with SQL Server that results in it infinitely recompiling a function.
To reproduce, create a new database with the option Parameterization = Forced or execute the following on an existing DB:
ALTER DATABASE [DatabaseName] SET PARAMETERIZATION FORCED WITH NO_WAIT
Then execute the following script:
CREATE TABLE dbo.TestTable(
ID int IDENTITY(1,1) NOT NULL,
FullTextField varchar(100) NULL,
CONSTRAINT PK_TestTable PRIMARY KEY CLUSTERED
(ID ASC)
)
GO
IF NOT EXISTS(SELECT 1 FROM sysfulltextcatalogs WHERE name = 'FullTextCat')
CREATE FULLTEXT CATALOG FullTextCat;
GO
CREATE FULLTEXT INDEX ON dbo.TestTable (FullTextField) KEY INDEX PK_TestTable
ON FullTextCat
WITH
CHANGE_TRACKING AUTO
GO
CREATE OR ALTER FUNCTION dbo.fn_TestFullTextSearch(#Filter VARCHAR(8000))
RETURNS TABLE
AS
RETURN SELECT
ID,
FullTextField
FROM dbo.TestTable
WHERE CONTAINS(FullTextField, #Filter)
GO
SELECT * FROM dbo.fn_TestFullTextSearch('"a*"')
The query will never return. Running SQL Profiler to monitor SP:CacheInsert and SP:CacheRemove will show SQL server is doing this endlessly and the SQL logs will show countless "A possible infinite recompile was detected for SQLHANDLE" messages.
Setting the Parameterization = Simple works around the issue but we need this to be set to Forced for other reasons.
Has anyone come across this issue before and/or have a suggested solution?
Thanks,
Chuck
While I still experience the problem with the original code I provided, by following #Martin's approach of explicitly parameterizing the call to the function:
EXEC sys.sp_executesql N'SELECT * FROM dbo.fn_TestFullTextSearch(#Filter)', N'#Filter VARCHAR(4)', #Filter = '"a*"'
I have been able to successfully work around the problem.

SQL Server - Schrödinger's View

I can't create/alter a VIEW because it already exists.
I also can't drop the same VIEW because it does not exists!
First of all, I'm SA on a SQL Server 2012.
CREATE VIEW [dbo].[some_name]
There is already an object named 'some_name' in the database.
DROP VIEW [dbo].[some_name]
Cannot drop the view 'dbo.some_name', because it does not exist or you
do not have permission.
SELECT OBJECT_ID(N'dbo.some_name', N'V')
SELECT OBJECT_ID('dbo.some_name', 'V')
SELECT OBJECT_ID(N'dbo.some_name')
SELECT OBJECT_ID('dbo.some_name')
SELECT OBJECT_ID(N'some_name')
SELECT OBJECT_ID('some_name')
NULL (for each query)
SELECT * FROM sys.objects WHERE name LIKE '%some_name%'
SELECT * FROM sys.objects WHERE name ='some_name'
SELECT * FROM sys.objects WHERE name = N'some_name'
empty result (for each query)
SELECT * FROM fn_my_permissions(N'dbo.some_name','OBJECT')
SELECT * FROM fn_my_permissions('dbo.some_name','OBJECT')
SELECT * FROM fn_my_permissions(N'some_name','OBJECT')
SELECT * FROM fn_my_permissions('some_name','OBJECT')
SELECT * FROM fn_my_permissions(N'some_name','VIEW')
SELECT * FROM fn_my_permissions('some_name','VIEW')
empty result (for each query)
Alt+F1 on 'some_name':
The object 'some_name' does not exist in database 'X' or is invalid
for this operation.
EXEC sp_rename
#objname = 'other_name',
#newname = 'some_name'
Error: The new name 'some_name' is already in use as a object name and
would cause a duplicate that is not permitted.
EXEC sp_rename
#objname = 'some_name',
#newname = 'other_name'
No item by the name of 'some_name' could be found in the current
database 'X', given that #itemtype was input as '(null)'.
And now something interesting. If I run:
DROP FUNCTION [dbo].[some_name]
DROP SYNONYM [dbo].[some_name]
DROP TABLE [dbo].[some_name]
DROP TRIGER[dbo].[some_name]
DROP TYPE [dbo].[some_name]
DROP VIEW [dbo].[some_name]
I get only 5 messages:
Cannot drop the [FUNCTION, SYNONYM, TABLE, TRIGGER, TYPE]
'dbo.some_name', because it does not exist or you do not have
permission. (no mention of the VIEW)
But if I move the View command to the top :
DROP VIEW [dbo].[some_name]
DROP FUNCTION [dbo].[some_name]
DROP SYNONYM [dbo].[some_name]
DROP TABLE [dbo].[some_name]
DROP TRIGER[dbo].[some_name]
DROP TYPE [dbo].[some_name]
I get 6 messages, as expected.
Please help.
UPDATE
After a few CHECKDB commands I found what seems to be the problem. As suspected, this view is in an unconsistend state. By the DBCC command log I got the object_id of it. It does not existis on sys.objects, but it does existis on sys.columns. So, there are a few orphan columns on my database, which indicates a failure when creating or dropping this object.
So, by running DBCC CHECKCATALOG (and a few other DBCC commands) I got the messages:
Msg 3853, State 1: Attribute
(referenced_major_id=859202161,referenced_minor_id=42) of row
(class=0,object_id=990678627,column_id=0,referenced_major_id=859202161,referenced_minor_id=42)
in sys.sql_dependencies does not have a matching row
(object_id=859202161,column_id=42) in sys.columns.
Msg 8956, Level 16, State 1, Line 1 Index row (1:123:12) with values
(nsclass = 0 and nsid = 1 and name = 'some_name') points to the data
row identified by (RID = (1:456:45)).
SOLUTION
0 - Backup your database.
1 - Reboot your server on Single User Mode (-m parameter)
2 - Set the database to Single User Mode:
ALTER DATABASE X
SET SINGLE_USER
WITH ROLLBACK IMMEDIATE;
GO
3 - Run a CHECKDB command with a repair option. In my case it was:
DBCC CHECKDB (X,REPAIR_REBUILD)
4 - Set the database back to Multi User Mode
ALTER DATABASE X
SET MULTI_USER
WITH ROLLBACK IMMEDIATE;
GO
'X' is the name of the database.
I'm not sure if step 0 and 1 are really necessary, but better safe than sorry.
You may find more info about the CHECKDB command and its repair otions at: DBCC CHECKDB
I think SQL server requires that object names be unique. You certainly cannot have a table and a view with the same name, as it would be impossible to distinguish which object was intended when you refer to it. But I think function and procedure names also have to be unique ( and this may not be strictly necessary, as far as I know the context in which these names are used always allows them to be distinguished ).
From your error messages, I understand that dbo.some_name exists, but, you don't have enough permissions to view dbo.some_name.
sys.objects will show only the objects, to which you have got permission to view .MSDN reference
Permissions
The visibility of the metadata in catalog views is limited
to securables that a user either owns or on which the user has been
granted some permission.
You can see what permissions you have got on an object by running the below query:
SELECT * FROM fn_my_permissions('dbo.some_name','OBJECT')
You need to have CONTROL permission to drop it. You need to have ALTER permission to rename the object.
UPDATE
can you please again check whether you are part of sysadmin role at server level and part of db_owner role at db level (sysadmins enter database as db_owners).
use database_name
go
SELECT Is_srvrolemember('sysadmin')
select IS_ROLEMEMBER('db_owner')

ANSI Warnings on Amazon RDS SQL Server not setting

I have strange problem in an AWS RDS SQL Server database I have spun up and I can't figure out what is going on.
Test 1
create table #tmp
(test varchar(10) null)
insert into #tmp
select 'asfsadfasdsafdafas'
select * from #tmp
drop table #tmp
Results in:
Msg 8152, Level 16, State 14, Line 5
String or binary data would be truncated.
(0 row(s) affected)
Test 2
set ANSI_WARNINGS OFF
create table #tmp1
(test varchar(10) null)
insert into #tmp1
select 'asfsadfasdsafdafas'
select * from #tmp1
drop table #tmp1
Results in:
------------------
asfsadfasd
When I look at the database properties it says that ANSI Warnings Enabled is set to FALSE, however, the database does not appear to be behaving as expected.
Any help would be appreciated.
EDIT:
Another Example might help
ALTER DATABASE test_db
set QUOTED_IDENTIFIER OFF
go
select "hello"
Results in:
Msg 207, Level 16, State 1, Line 5
Invalid column name 'hello'.
Thanks
--The Issue Occur Because of Length Of Datatype
create table #tmp1
(test varchar(50) null)
insert into #tmp1
select 'asfsadfasdsafdafas'
select * from #tmp1
drop table #tmp1
--==============================
When create or alter SQL object like Stored Procedure, User Defined Function in Query Analyzer, it is created with following SQL commands prefixed and suffixed. What are these – QUOTED_IDENTIFIER ON/OFF and ANSI_NULL ON/OFF?
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_NULLS ON
GO--SQL PROCEDURE, SQL FUNCTIONS, SQL OBJECTGO
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO
ANSI NULL ON/OFF:
This option specifies the setting for ANSI NULL comparisons. When this is on, any query that compares a value with a null returns a 0. When off, any query that compares a value with a null returns a null value.
QUOTED IDENTIFIER ON/OFF:
This options specifies the setting for usage of double quotation. When this is on, double quotation mark is used as part of the SQL Server identifier (object name). This can be useful in situations in which identifiers are also SQL Server reserved words.

How do I make ALTER COLUMN idempotent?

I have a migration script with the following statement:
ALTER TABLE [Tasks] ALTER COLUMN [SortOrder] int NOT NULL
What will happen if I run that twice? Will it change anything the second time? MS SQL Management Studio just reports "Command(s) completed successfully", but with no details on whether they actually did anything.
If it's not already idempotent, how do I make it so?
I would say that second time, SQL Server checks metadata and do nothing because nothing has changed.
But if you don't like possibility of multiple execution you can add simple condition to your script:
CREATE TABLE Tasks(SortOrder VARCHAR(100));
IF NOT EXISTS (SELECT 1
FROM INFORMATION_SCHEMA.COLUMNS
WHERE [TABLE_NAME] = 'Tasks'
AND [COLUMN_NAME] = 'SortOrder'
AND IS_NULLABLE = 'NO'
AND DATA_TYPE = 'INT')
BEGIN
ALTER TABLE [Tasks] ALTER COLUMN [SortOrder] INT NOT NULL
END
SqlFiddleDemo
When you execute it the second time, the query gets executed but since the table is already altered, there is no effect. So it makes no effect on the table.
No change is there when the script executes twice.
Here is a good MSDN read about: Inside ALTER TABLE
Let's look at what SQL Server does internally when performing an ALTER
TABLE command. SQL Server can carry out an ALTER TABLE command in any
of three ways:
SQL Server might need to change only metadata.
SQL Server might need to examine all the existing data to make sure
it's compatible with the change but then change only metadata.
SQL Server might need to physically change every row.

Use the result of a system stored procedure as a queryable table

Note: the highest linked question does not solve the problem for system stored procedures, but it's close. With help of the commenters, I came to a working answer.
Trying to use statements such as the following for sp_spaceused, throws an error
SELECT * INTO #tblOutput exec sp_spaceused 'Account'
SELECT * FROM #tblOutput
The errors:
Must specify table to select from.
and:
An object or column name is missing or empty. For SELECT INTO statements, verify each column has a name. For other statements, look for empty alias names. Aliases defined as "" or [] are not allowed. Change the alias to a valid name.
When I fully declare a table variable, it works as expected, so it seems to me that the stored procedure does return an actual table.
CREATE TABLE #tblOutput (
name NVARCHAR(128) NOT NULL,
rows CHAR(11) NOT NULL,
reserved VARCHAR(18) NOT NULL,
data VARCHAR(18) NOT NULL,
index_size VARCHAR(18) NOT NULL,
unused VARCHAR(18) NOT NULL)
INSERT INTO #tblOutput exec sp_spaceused 'Response'
SELECT * FROM #tblOutput
Why is it not possible to use a temp table or table variable with the result set of EXECUTE sp_xxx? Or: does a more compact expression exist than having to predefine the full table each time?
(incidentally, and off-topic, Googling for the exact term SELECT * INTO #tmp exec sp_spaceused at the time of writing, returned exactly one result)
TL;DR: use SET FMTONLY OFF with OPENQUERY, details below.
It appears that the link provided by Daniel E. is only part of the solution. For instance, if you try:
-- no need to use sp_addlinkedserver
-- must fully specify sp_, because default db is master
SELECT * FROM OPENQUERY(
[SERVERNAME\SQL2008],
'exec somedb.dbo.sp_spaceused ''Account''')
you will receive the following error:
The OLE DB provider "SQLNCLI10" for linked server "LOCALSERVER\SQL2008" supplied inconsistent metadata for a column. The name was changed at execution time.
I found the solution through this post, and then a blog-post on OPENQUERY, which in turn told me that until SQL2008, you need to use SET FMTONLY OFF. The final solution, which is essentially surprisingly simple (and easier to accomplish since there is no need to specify a loopback linked server), is this:
SELECT * FROM OPENQUERY(
[SERVERNAME\SQL2008],
'SET FMTONLY OFF
EXEC somedb.dbo.sp_spaceused ''Account''')
In addition, if you haven't set DATA-ACCESS, you may get the following error:
Server 'SERVERNAME\SQL2008' is not configured for DATA ACCESS.
This can be remedied by running the following command:
EXEC sp_serveroption 'SERVERNAME\SQL2008', 'DATA ACCESS', TRUE
We cannot SELECT from a stored procedure thats why SELECT * INTO ..Exec sp_ will not work.
To get the result set returned from a store procedure we can INSERT INTO a table.
SELECT INTO statement creates a table on fly and inserts data from the source table/View/Function. The only condition is source table should exist and you should be able to Select from it.
Sql Server doesn't allow you to use SELECT from sp_ therefore you can only use the INSERT INTO statement when executing a stored procedure this means at run time you can add the returned result set into a table and Select from that table at later stage.
INSERT INTO statement requires the destination table name, An existing table. Therefore whether you use a Temp Table, Table variable or Sql server persistent table you will need to create the table first and only they you can use the syntax
INSERT INTO #TempTable
EXECUTE sp_Proc
Using [YOUR DATABASE NAME]
CREATE TABLE [YOURTABLENAME]
(Database_Name Varchar(128),
DataBase_Size VarChar(128),
unallocated_Space Varchar(128),
reserved Varchar(128),
data Varchar(128),
index_size Varchar(128),
unused Varchar(128)
);
INSERT INTO dbo.[YOUR TABLE NAME]
(
Database_Name,
DataBase_Size,
unallocated_Space,
reserved,
data,
index_size,
unused
)
EXEC sp_spaceused #oneresultset = 1
--To get it to return it all as one data set add the nonresultset=1 at the end and viola good to go for writing to a table. :)

Resources