On my local machine, I am unable to drop a table because it doesn't exist or I don't have permission - sql-server

I am going through college and I'm doing an database class where we're introduced to the SQL Server Management Studio, so I'm very new to all of this. That being said, I've been following along and keeping up, making sure to note his queries... However, I noticed something. In the queries I've been making while keeping notes of my class, I have the error "cannot drop table because it does not exist or you don't have permissions".
Now this is odd to me, as I am the only user of this laptop, I am basically the administrator, I've created the database and tables as per instructions and yet, this issue is popping up and I'm unable to run my queries to see how they work.
Here's a snippet of my code, though I'm not sure how much it'd help...
-- Dropping tables in case they already exist
drop table Movie
drop table Genre
drop table Theater
drop table MovieTheater
-- Create table
create table Movie
(
MovieID int not null constraint PK_Movie primary key,
Title varchar(200) not null,
Budget money null,
ReleaseDate date null,
GenreCode char(1) not null constraint FK_MovieToGenre references Genre(GenreCode),
Released bit not null,
MovieLength decimal(5,2) null
)
create table Genre
(
GenreCode char(1) not null constraint PK_Genre primary key,
GenreDescription varchar(30) not null
)
create table Theater
(
TheaterID int not null constraint PK_Theater primary key,
TheaterName varchar(100) not null,
Address varchar(50) not null,
City varchar(50) not null,
Province char(2) not null,
PostalCode char(7) not null,
PhoneNumber char(13) not null
)
create table MovieTheater
(
MovieID int not null,
TheaterID int not null,
StartDate date not null,
EndDate date null,
constraint PK_MovieTheater primary key (MovieID, TheaterID)
)
I attempted changing the permissions of the database but it wouldn't allow me. Other solutions I've looked up all assume that it's connecting to a database for other purposes (likely work related)

The error is pretty clear. cannot drop table because it does not exist. You can't DROP a table that doesn't exist, just as you can't CREATE a table that already exists.
In SQL Server 2016 and later you can use DROP TABLE IF EXISTS to drop a table if it exists. Since the oldest version in mainstream support is SQL Server 2019, you can reasonably expect that IF EXISTS will work on any new database
DROP TABLE IF EXISTS [dbo].[MyTable0];
In older, now unsupported, versions you had to check explicitly in an IF :
IF OBJECT_ID(N'dbo.MyTable0', N'U') IS NOT NULL
DROP TABLE [dbo].[MyTable0];
The SQL Server DROP TABLE IF EXISTS Examples shows all these options. Use DROP TABLE IF EXISTS unless you really need to work with an unsupported database version.

From your code, I think the problem is you tried to drop the tables before you created them
-- Dropping tables in case they already exist
drop table Movie
drop table Genre
drop table Theater
drop table MovieTheater
To drop the table if only it has already exist, you could try:
IF OBJECT_ID('tableName', 'U') IS NOT NULL
DROP TABLE tableName;
Explain:
The OBJECT_ID function returns the object ID of the specified table. If the table does not exist, it returns NULL. The 'U' parameter indicates that we are looking for a user-defined table.
The IF statement checks whether the table exists by checking the result of the OBJECT_ID function. Simple as that!

Related

Getting an "Invalid object name" error in ADS after creating a new table

I'm working on a new Jupyter Notebook, using SQL as the Kernel, to create a new table, populate it with a couple records, etc., then drop the table. I've written the CREATE TABLE DDL, then ran it. However, when I ran it in ADS it gave me an error on the table name ("Invalid object name ") and each column in the new table ("Invalid column name "). But it created the table, nonetheless. Huh? What's going on?
I've looked for similar questions posted here on SO, but none of the match my situation. For example, one of them the user had created the table as one name, but then tried to do a SELECT against a different table name, that was slightly different from the one they created. That's not the case for me. Here's the SQL DDL for creating the table:
IF OBJECT_ID('[dbo].[Bozo]', 'U') IS NOT NULL
DROP TABLE [dbo].[Bozo]
GO
-- Create the table in the specified schema
CREATE TABLE [dbo].[Bozo]
(
[Id] INT NOT NULL PRIMARY KEY, -- Primary Key column
[FirstName] NVARCHAR(50) NOT NULL,
[LastName] NVARCHAR(50) NOT NULL,
-- Specify more columns here
Bool1 BIT DEFAULT 1,
Bool2 BIT DEFAULT 1,
BoolValue AS Bool1 & Bool2
);
GO
And here's my SQL INSERT statements:
NSERT INTO Bozo (FirstName, LastName)
VALUES ('George', 'Washington');
INSERT INTO Bozo (FirstName, LastName, Bool2)
VALUES ('John', 'Adams', 0);
I discovered that the SQL Script that Azure Data Studio uses to create a new table does not define the Id column as an IDENTITY column. Changing that fixed the issue, so now it is:
IF OBJECT_ID('[dbo].[Bozo]', 'U') IS NOT NULL
DROP TABLE [dbo].[Bozo]
GO
-- Create the table in the specified schema
CREATE TABLE [dbo].[Bozo]
(
[Id] INT IDENTITY(1,1) NOT NULL PRIMARY KEY, -- Primary Key column
[FirstName] NVARCHAR(50) NOT NULL,
[LastName] NVARCHAR(50) NOT NULL,
-- Specify more columns here
Bool1 BIT DEFAULT 1,
Bool2 BIT DEFAULT 1,
BoolValue AS Bool1 & Bool2
);
GO

Is it safe to add IDENTITY PK Column to existing SQL SERVER table?

After rebuilding all of the tables in one of my SQL SERVER databases, into a new database, I failed to set the 'ID' column to IDENTITY and PRIMARY KEY for many of the tables. Most of them have data.
I discovered this T-SQL, and have successfully implemented it for a couple of the tables already. The new/replaced ID column contains the same values from the previous column (simply because they were from an auto-incremented column in the table I imported from), and my existing stored procedures all still work.
Alter Table ExistingTable
Add NewID Int Identity(1, 1)
Go
Alter Table ExistingTable Drop Column ID
Go
Exec sp_rename 'ExistingTable.NewID', 'ID', 'Column'
--Then open the table in Design View, and set the new/replaced column as the PRIMARY KEY
--I understand that I could set the PK when I create the new IDENTITY column
The new/replaced ID column is now the last column in the table, and so far, I haven't ran into issues with the ASP.Net/C# data access objects that call the stored procedures.
As mentioned, each of these tables had no PRIMARY KEY (nor FOREIGN KEY) set. With that in mind, are there any additional steps I should take to ensure the integrity of the database?
I ran across this SO post, which suggests that I should run the 'ALTER TABLE REBUILD' statement, but since there was no PK already set, do I really need to do this?
Ultimately, I just want to be sure I'm not creating issues that won't appear until later in the game, and be sure the methods I'm implementing are sound, logical, and ensure data integrity.
I suppose it might be a better option to DROP/RECREATE the table with the proper PK/IDENTITY column, and I could write some T-SQL to dump the existing data into a TEMP table, then drop/recreate, and re-populate the new table with data from the TEMP table. I specifically avoided this option as it seems much more aggressive, and I don't fully understand what it means for the Stored Procedures/Functions, etc., that depend on these tables.
Here is an example of one of the tables I've performed this on. You can see the NewID values are identical to the original ID.enter image description here
Give this a go; it's rummaged up from a script we used a few years ago in a similar situation, can't remember what version of SQLS it was used against.. If it works out for your scenario you can adapt it to your tables..
SELECT MAX(Id)+1 FROM causeCodes -- run and use value below
CREATE TABLE [dbo].[CauseCodesW]( [ID] [int] NOT NULL IDENTITY(put_maxplusone_here,1), [Code] [varchar](50) NOT NULL, [Description] [varchar](500) NULL, [IsActive] [bit] NOT NULL )
ALTER TABLE CauseCodes SWITCH TO CauseCodesW;
DROP TABLE CauseCodes;
EXEC sp_rename 'CauseCodesW','CauseCodes';
ALTER TABLE CauseCodes ADD CONSTRAINT PK_CauseCodes_Id PRIMARY KEY CLUSTERED (Id);
SELECT * FROM CauseCodes;
You can now find any tables that have FKs to this table and recreate those relationships..

How do I create system versioned tables using SSDT in Visual Studio 2019?

I'm trying to create Table with system versioning using Database Project.
Following schema gives error:
SQL70633: System-versioned temporal table must have history table name explicitly provided.
CREATE TABLE [dbo].[Products]
(
[Id] INT NOT NULL PRIMARY KEY,
[Name] NVARCHAR(255) NOT NULL,
[ModifiedBy] NVARCHAR(127) NULL
)
WITH (SYSTEM_VERSIONING = ON)
GO
With explicit name:
SQL71501: Table: [dbo].[Products] has an unresolved reference to Table [history].[ProductsHistory].
SQL46010: Incorrect syntax near ].
CREATE TABLE [dbo].[Products]
(
[Id] INT NOT NULL PRIMARY KEY,
[Name] NVARCHAR(255) NOT NULL,
[ModifiedBy] NVARCHAR(127) NULL
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = [history].ProductsHistory))
GO
I've tried both, latest version of Visual Studio 2019 (16.7.5) and latest preview (16.8.0 Preview 3.2).
The syntax in both cases is invalid. Executing the first query in SSMS returns:
Cannot set SYSTEM_VERSIONING to ON when SYSTEM_TIME period is not defined.
The command needs a PERIOD FOR SYSTEM_TIME clause specifying the columns used to specify the validity period of a record.
The documentation examples show how to create a temporal table with a default, automatically named history table :
CREATE TABLE [dbo].[Products]
(
[Id] INT NOT NULL PRIMARY KEY,
[Name] NVARCHAR(255) NOT NULL,
[ModifiedBy] NVARCHAR(127) NULL,
SysStartTime DATETIME2 GENERATED ALWAYS AS ROW START NOT NULL,
SysEndTime DATETIME2 GENERATED ALWAYS AS ROW END NOT NULL,
PERIOD FOR SYSTEM_TIME (SysStartTime,SysEndTime)
)
WITH (SYSTEM_VERSIONING = ON)
In this case, the SysStartTime and SysEndTime are used to specify the validity period of a record.
Similar syntax is needed to create a temporal table with a user-specified table name
create TABLE [dbo].[Products]
(
[Id] INT NOT NULL PRIMARY KEY,
[Name] NVARCHAR(255) NOT NULL,
[ModifiedBy] NVARCHAR(127) NULL,
SysStartTime DATETIME2 GENERATED ALWAYS AS ROW START NOT NULL,
SysEndTime DATETIME2 GENERATED ALWAYS AS ROW END NOT NULL,
PERIOD FOR SYSTEM_TIME (SysStartTime,SysEndTime)
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.ProductHistory))
It's possible to create the history table on a different schema, eg history, as long as that schema exists, BUT it's probably not a good idea unless this solves some specific problem. The current and history table represent the same entity, depend on each other and have specific security restrictions so storing them in separate schemas can make life harder.
To create the table in a separate schema, first create the schema :
CREATE SCHEMA history
Then use the schema in the table definition:
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = history.ProductHistory))

Is there any way to track changes from views in MS Sql Server?

I'm looking for how to track changes from a view in MS Sql-Server 2012. And, the role of the log-in user is Public. So, it's hard to do it.
For example, Assuming that there is the schema.
CREATE TABLE [dbo].[USER_CREDENTIAL](
[USERID] [nvarchar](48) NOT NULL,
[VALID_FROM] DATETIME NULL,
[EXPIRED_AT] DATETIME NULL,
[CREDENTIAL_ID] int NOT NULL,
CONSTRAINT [UNIQUE_USERID] PRIMARY KEY CLUSTERED( [USERID] ASC)
) ;
CREATE VIEW [VIEW_OF_USER_CREDENTIAL] as
SELECT * FROM dbo.[USER_CREDENTIAL];
It can be only permitted to access the view. The view will be changed when some data is inserted/updated/deleted from the USER_CREDENTIAL table. I will do query to the view.
I saw the document. I tried that, but the target to track should be the data table and the login user is lack of the role. I got the error message.
Object 'foo' is of a data type that is not supported by the CHANGETABLE function. The object must be a user-defined table.
I tried the following. I added the temporary table and the trigger which make changed-data be inserted to the temporary table when the view is changed. But, it was also failed because it was permission denied.
CREATE TABLE dbo.[CHANGES_FROM_A_VIEW] (
[VERSION] [int] IDENTITY(1,1) NOT NULL,
[USERID] [nvarchar](48) NOT NULL,
CONSTRAINT [UNIQUE_VERSION] PRIMARY KEY CLUSTERED ( [VERSION] ASC)
)
CREATE TRIGGER [SOMETHING_CHANGED] ON dbo.[VIEW_OF_USER_CREDENTIAL] ...
ALTER DATABASE database_name
SET CHANGE_TRACKING = ON (CHANGE_RETENTION = 2 DAYS,AUTO_CLEANUP = ON)
ALTER TABLE [CHANGES_FROM_A_VIEW]
ENABLE CHANGE_TRACKING WITH (TRACK_COLUMNS_UPDATED = ON)
SELECT * FROM CHANGETABLE(CHANGES dbo.CHANGES_FROM_A_VIEW, 0) AS C
Anyone knows any way to solve this?

INSTEAD OF UPDATE Trigger and Updating the Primary Key

I am making changes to an existing database while developing new software. There is also quite a lot of legacy software that uses the database that needs to continue working, i.e. I would like to maintain the existing database tables, procs, etc.
Currently I have the table
CREATE TABLE dbo.t_station (
tx_station_id VARCHAR(4) NOT NULL,
tx_description NVARCHAR(max) NOT NULL,
tx_station_type CHAR(1) NOT NULL,
tx_current_order_num VARCHAR(20) NOT NULL,
PRIMARY KEY (tx_station_id)
)
I need to include a new field in this table that refers to a Plant (production facility) and move the tx_current_order_num to another table because it is not required for all rows. So I've created new tables:-
CREATE TABLE Private.Plant (
PlantCode INT NOT NULL,
Description NVARCHAR(max) NOT NULL,
PRIMARY KEY (PlantCode)
)
CREATE TABLE Private.Station (
StationId VARCHAR(4) NOT NULL,
Description NVARCHAR(max) NOT NULL,
StationType CHAR(1) NOT NULL,
PlantCode INT NOT NULL,
PRIMARY KEY (StationId),
FOREIGN KEY (PlantCode) REFERENCES Private.Plant (PlantCode)
)
CREATE TABLE Private.StationOrder (
StationId VARCHAR(4) NOT NULL,
OrderNumber VARCHAR(20) NOT NULL,
PRIMARY KEY (StationId)
)
Now, I don't want to have the same data in two places so I decided to change the dbo.t_station table into a view and provide instead of triggers to do the DELETE, INSERT and UPDATE. No problem I have [most of] them working.
My question regards the INSTEAD OF UPDATE trigger, updating the Primary Key column (tx_station_id) and updates to multiple rows.
Inside the trigger block, is there any way to join the inserted and deleted [psuedo] tables so that I know the 'before update primary key' and the 'after update primary key'? Something like this...
UPDATE sta
SET sta.StationId = ins.tx_station_id
FROM Private.Station AS sta
INNER JOIN deleted AS del
INNER JOIN inserted AS ins
ON ROW_IDENTITY_OF(del) = ROW_IDENTITY_OF(ins)
ON del.tx_station_id = sta.StationId
At this stage I've put a check in the trigger block that rollbacks the update if the primary key column is updated and there is more than one row in the inserted, or deleted, table.
The short answer is no.
You could put a surrogate key on Private.Station, and expose that through the view, and use that to identify before and after values. You wouldn't need to change the primary key or foreign key relationship, but you would have to expose some non-updateable cruft through the view, so that it showed up in the pseudo-tables. eg:
alter table Private.Station add StationSk int identity(1,1) not null
Note, this may break the legacy application if it uses SELECT *. INSERT statements without explicit insert column lists should be ok, though.
Short of that, there may be some undocumented & consistent ordering between INSERTED and DELETED, such that ROW_NUMBER() OVER (ORDER BY NULLIF(StationId,StationId)) would let you join the two, but I'd be very hesitant to take the route. Very, very hesitant.
Have you intentionally not enabled cascade updates? They're useful when primary key values can be updated. eg:
CREATE TABLE Private.Station (
StationId VARCHAR(4) NOT NULL,
Description NVARCHAR(max) NOT NULL,
StationType CHAR(1) NOT NULL,
PlantCode INT NOT NULL,
PRIMARY KEY (StationId),
FOREIGN KEY (PlantCode) REFERENCES Private.Plant (PlantCode)
ON UPDATE CASCADE
-- maybe this too:
-- ON DELETE CASCADE
)
Someone might have a better trick. Wait and watch!

Resources