ALTER VIEW gives invalid column name, but SELECT works fine - sql-server

I am trying to alter a view and I get the following error:
Msg 207, Level 16, State 1, Procedure PackingListInvalid column name 'NetLbs'.
That looks like a self explanatory message, but the problem is the column does exist. If I run the select that is part of the view it works perfectly fine.
This is my alter statement.
alter view [vw].[PackingList]
as
select b.Id,
b.NetLbs
from WorkOrderDetails d
join Boxes b on b.Id = d.BoxId
If I just execute this part it works fine.
select b.Id,
b.NetLbs
from WorkOrderDetails d
join Boxes b on b.Id = d.BoxId
I tried dropping the view and using create, but that failed also.
So then I created the view with this sql.
create view [vw].[PackingList] as select null as test
And the alter still fails.
However I learned that if I create the view in the dbo schema it works. I'm not sure what I should try next.

user3083310 suggested to put the schema in front of my tables. I did that and it works perfectly.
Also see this post from Aaron Bertrand to learn more about why you should do this.

Related

Display Results Before Delete SQL Server

I'm so close to getting the answer to this, but I feel like I'm missing the final part.
I've created a DELETE trigger that should display values from the SELECT statement before they are deleted from the table. However, when the trigger is called I get a blank result, but the values (order_id=10001 AND product_id=25) are still deleted from the table.
I've verified the SELECT statement works before I've run the trigger, so I'm confident that part is correct.
I've tried using an INSTEAD OF DELETE trigger, but the values end up not being deleted. I don't believe there is a BEFORE DELETE function for SQL Server? Is there a work around?
Suggestions?
CREATE TRIGGER deleteOrderTrigger
ON order_details
FOR DELETE
AS
SELECT order_details.product_id, products.name,
order_details.quantity AS 'Quantity being deleted from order',
SUM(products.quantity_in_stock) + order_details.quantity AS 'In Stock Quantity after Deletion'
FROM order_details
LEFT JOIN products ON products.product_id = order_details.product_id
WHERE order_details.order_id = 10001 AND products.product_id = 25
GROUP BY order_details.product_id, products.name, order_details.quantity
GO
-- Below is the code that will fire the trigger
DELETE order_details
WHERE order_id = 10001 AND product_id = 25
#JoeC - using a proc is probably the best answer.
If you must use a trigger then remmeber that it must be coded to support sets. If someone executes delete order_details where order_id = 10001 then your trigger will need to return the stock level for every product on the order.
Also, when coding a trigger, you have access to a built in table named deleted. This table contains the records deleted.
So you can do something like this:
CREATE TRIGGER deleteOrderTrigger
ON order_details
FOR DELETE
AS
INSERT INTO deleted_order_products_log
SELECT order_details.product_id
,products.name
,[Quantity being deleted from order] = order_details.quantity
,[In Stock Quantity after Deletion] = SUM(products.quantity_in_stock) + order_details.quantity
FROM order_details
INNER JOIN deleted d
ON order_details.primaryKey = d.primaryKey
LEFT JOIN products
ON products.product_id = order_details.product_id
GROUP BY order_details.product_id
,products.name
,order_details.quantity;
You can then query the log file to get the results of the calculation.
I haven't used triggers a lot, but it seems you have an AFTER trigger, which is not able to read the deleted rows, that's why you get blank result.
The thing with triggers are the inserted and deleted tables, maybe this would help: https://learn.microsoft.com/en-us/sql/relational-databases/triggers/use-the-inserted-and-deleted-tables
You need a INSTEAD OF trigger as you mentioned, but you have to do the delete operation yourself. More on this subject here: https://learn.microsoft.com/en-us/sql/relational-databases/triggers/dml-triggers and one example in here: https://stackoverflow.com/a/3267726/5605866
Put the trigger results into an audit table and you will see the results of the trigger. I have never seen a trigger with a where clause similar to yours.
Do a insert into table x select.... You also want to use the deleted table(there is an inserted table) that is created just for each occurrence of the trigger that will contain any/all of the rows that were just deleted. The delete occurs in the main body of the code. The trigger is then invoked and the deleted table (you can do a delete * from deleted only in the trigger) that will contain the row(s) that were deleted.

T-SQL table creation in source

I'm starting a new SQL Server Azure DB from scratch. I want to establish a strong source control so I want to be careful in how I create all my tables.
What is the best method to check if the table exists and only execute my CREATE TABLE statement if it does not exist yet? I'm working with passing dynamic SQL to a stored procedure that checks for the tables existence, but that is so limiting. There has to be a preferred way to do this out there. I mean I could preface every query with:
IF NOT EXISTS (SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].j[myTable]') AND type in(N'U'))
BEGIN
CREATE TABLE myTable(....)
END
But that's pretty repetitive.
More simply:
IF NOT EXISTS (SELECT * FROM sys.tables WHERE Name = N'myTable')
CREATE TABLE myTable .......
Idea: use the more focused sys.tables catalog view, instead of the all-encompassing sys.objects - then you don't have to remember those rather unintuitive type values..... - but yes, that is the safest way to do this kind of code.
As of SQL Server 2016, you can also use the
DROP TABLE IF EXISTS myTable;
CREATE TABLE myTable .......
command (which is new - see here: https://blogs.msdn.microsoft.com/sqlserverstorageengine/2015/11/03/drop-if-exists-new-thing-in-sql-server-2016/)

What is the syntax of stored procedure in SQL Server 2012

I am trying to do a simple inner join to select a row or even just get ID from inner join of 2 tables, one is the regular ASP.NET users table and the other one is mine (interpreters) somehow my syntax is not accessible -
http://pastebin.com/4aDPrtst
I think it expect something like
[Common].[tbl_Interpreter_Account].[AspNetUsers]
with all the [][][][ but I am not sure
Assuming [Common] is your database schema and [AspNetUsers] is the table automatically created using membership services (or by some other means), I'm unsure what [tbl_Interpreter_Account] refers to. Could you please clarify?
Also the join needs to be corrected.
You're joining what appears to be the following two tables: AspNetUsers and AddIntrepeter. But the join condition is on some other table Interpreter_Account
Try the following:
Insert your databasename at the top of the procedure.
USE [Common]
CREATE PROCEDURE [dbo].[GetIntIdByEmail]
#email nvarchar(50)
AS
SELECT
AspNetUsers.UserName
FROM [AspNetUsers] users
INNER JOIN [<<Your_Table>>] interpreter ON users.Id = interpreter.<<your_Matching_Column>>
WHERE interpreter.contact_email = #email
GO

Change sql server query so you don't have to specify all levels to the database

What I want to do is instead of writing:
Select something From [Parent].[dbo].[Table]
I want to declare the first 2 before I write the query, so when I have to use several selects I don't have to specify [parent].[dbo] all the time. What I remember is that you can do something like this:
use [parent].[dbo]
select something From tabel
This seems to generate a warning 102, at the ".". I've tried googling this but all I get is "use" while doing generated queries, nothing to do with database names.
The dbo part is implied. Just do this:
use [parent]
select something From tabel
As Damien_The_Unbeliever pointed out, the dbo part is only implied if dbo is the user's default schema.
Parent must be your Database.
So if you want to use a particular database without specifying it:
use [DataBase]
DBO is implied, but if you want to use another schema, you will need to specify the schema in your SQL, ala newschema.Table1
In case you aren't using it, you can also reduce the clutter in your code by using aliases for your tables, ala
SELECT a.Column1, a.Column2
FROM table1 a JOIN
table2 b ON a.Column1 = b.Column1
WHERE a.column1 = 'SomeValue'
where the a that follows the table1 is an alias for table1, basically your giving the table a nickname for this query. Same thing for the b, it is an alias for table2. This is much less cluttered than SELECT table1.Column1, table1.Column2 FROM table1

Sql Server: how to write trigger on a table with denied SELECT

Hello I have a table on which I have denied SELECT privs to a user.
This table has a trigger which references the INSERTED table, basically doing an
AFTER UPDATE SET <table>.[UPDATED] = getdate()
WHERE ROWID IN SELECT ROWID FROM INSERTED
It is giving me an error though, saying "SELECT PERMISSIONS DENIED", I am guessing because of the SELECT FROM INSERTED.
How can I keep the SELECT deny, but allow the trigger to SELECT from the INSERTED pseudotable?
Thanks in advance!
Consider adding an EXECUTE AS clause so the trigger runs with the schema owner's permissions.
CREATE TRIGGER [dbo].[TR_Product_Update] ON [Product]
WITH EXECUTE AS OWNER
AFTER UPDATE
AS
SELECT ProductId
FROM INSERTED
Why did you deny select? What about just not granting select to them? There is a subtle difference between denying select and just not granting it to them. Also, if you denied select to any of the system level roles, then that would also probably be part of the problem.
--EDIT--
In the comments you asked whether or not SQL Server has context info. 2005 does and you can see how to use it here.
Session Variable – Context_Info: Session is a powerful tool in any of the programming language. SQL-Server is not a full fledge programming language but it do supports session variable for current session or connection. It stores value of session in 128 byte of binary information.
join to the inserted table instead something like:
update t1
set updated = getdate()
from table1 t1
join inserted i
on i.rowid = t1.rowid
This will probaly also perfom better than a subselect anyway.
I suspect your problem is that your UPDATE statement itself requires the SELECT permission.
I created a test database as follows:
DROP DATABASE triggerPermissionTest
CREATE DATABASE triggerPermissionTest
GO
USE triggerPermissionTest
GO
CREATE USER foo FROM LOGIN tester
GO
CREATE TABLE triggerTable (id int)
GO
DENY SELECT ON triggerTable to foo
GRANT UPDATE ON triggerTable to foo
GO
CREATE TRIGGER execAsTrigger ON triggerTable
AFTER UPDATE AS SELECT * FROM triggerTable
GO
INSERT INTO triggerTable VALUES (1)
GO
and tried the following Update statements with the 'tester' login:
UPDATE triggerTable SET id = 2
GO
UPDATE triggerTable SET id = id *2
GO
The first one executes fine and the trigger executes (providing the results of select * from triggerTable to the user without select permissions, demonstrating that it managed to do a select).
The second one gives me an error stating that I don't have select permission on triggerTable (because it needs to select from triggerTable in order to get the value of id to do the update).
This leads me to conclude that the trigger is incidental to the problem, and the UPDATE statement is the cause of the permission issue.

Resources