Issues with SQL Server functions and triggers - sql-server

I have been working on this project by using "advanced" features of SQL Server and creating functions, triggers, but two of these are giving me serious issues.
I am supposed to create a function that includes one input parameter and returns a table. The function itself will return a summary of the individual costs of each insurance expense (base, spouse, etc.), a total of those expenses and the employees name given the number of dependents a given employee has- the user enters the number of dependents as an input parameter.
CREATE FUNCTION fnInsCosts
(#NoDependants int)
--returns table datatype
RETURNS table
AS
--Set the Return to select the columns and aggregated columns from vwPayRoll as listed in exercise 3 of Module 12 --assignment sheet where Dependants is = to the input variable.
RETURN (SELECT
EmpName,
SUM(BaseCost) AS TotBaseCost, SUM(SpouseIns) AS TotSpouseCost,
SUM(DepIns) AS TotDepCost, SUM(DentalCost) AS TotDentalCost,
SUM(BaseCost * SpouseIns * DepIns * DentalCost) AS TotInsCost
FROM
vwPayroll
WHERE
Dependants = #NoDependants
GROUP BY
Dependants);
SELECT * FROM dbo.fnInsCosts(2);
SELECT * FROM dbo.fnInsCosts(0);-- Unfinished/error with select and EmpName?
Here is the error I get when I try to run the whole thing:
Msg 156, Level 15, State 1, Procedure fnInsCosts, Line 15
Incorrect syntax near the keyword 'SELECT'.
And it says this when I run everything except for the part where I invoke it:
Msg 8120, Level 16, State 1, Procedure fnInsCosts, Line 10
Column 'vwPayroll.EmpName' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
And here is the last one; I am creating a trigger and I need to create two table copies:
--Test for the existence of a fake table named TempEmpData. If it exists, drop it.
IF OBJECT ID('TempEmpData') IS NOT NULL
DROP TABLE TempEmpData;
--Test for the existence of a fake table named TempWork. If it exists, drop it.
IF OBJECT ID('TempWork') IS NOT NULL
DROP TABLE TempWork;
--Select everything from EmpData into the appropriate fake table
SELECT * INTO TempEmpData FROM EmpData
--Select everything from Work into the appropriate fake table
SELECT * INTO TempWork FROM Work
GO
CREATE TRIGGER TempEmpDate_INSERT_UPDATE_DELETE
ON TempEmpData
AFTER INSERT, UPDATE, DELETE
AS
--(USE THIS CONDITIONAL STRUCTURE- substitute variable names where needed and remove the "--")
IF EXISTS (SELECT * FROM Deleted JOIN TempEmpData ON Deleted.EmpID = TempEmpData.EmpID)
--the correct primary key)
BEGIN;
--Custom error message
THROW 11, 'EmpID is in use; transaction cancelled!', 1;
--rollback the transaction
ROLLBACK TRAN;
END;
ELSE
BEGIN
--Update the appropriate fake table
CREATE TRIGGER TempEmpData_INSERT_UPDATE
ON TempEmpData
AS
--Set the appropriate column to the correct value
--Where the correct primary key is in a subquery selecting that same key from the
--system table that handles inserts
UPDATE TempEmpData
SET BenPlanID = 0;
DELETE TempEmpData
WHERE EmpID = 41;
INSERT TempEmpData
VALUES ('Bill', 'Smith', '11/14/2014', 0, 0, 1, NULL, 2);
SELECT *
FROM TempEmpData
ORDER BY EmpID DESC
END;
And here are the errors:
Msg 4145, Level 15, State 1, Line 4
An expression of non-boolean type specified in a context where a condition is expected, near 'ID'.
Msg 4145, Level 15, State 1, Line 8
An expression of non-boolean type specified in a context where a condition is expected, near 'ID'.
Msg 156, Level 15, State 1, Procedure TempEmpDate_INSERT_UPDATE_DELETE, Line 17
Incorrect syntax near the keyword 'TRIGGER'.
I would be extremely grateful for any insight.

You are using the "new" inline syntax to create a function, great!
The first error comes from the missing "GO" to separate the creation of your function from the call to it
CREATE FUNCTION fnInsCosts()
--You function code here
GO
SELECT * FROM dbo.fnInsCosts(2);
The second error in your function has its reason - as stated by JamesZ already - in the wrong grouping column:
SELECT EmpName,
SUM(BaseCost) AS TotBaseCost,
SUM(SpouseIns) AS TotSpouseCost,
SUM(DepIns) AS TotDepCost,
SUM(DentalCost) AS TotDentalCost,
SUM(BaseCost * SpouseIns * DepIns * DentalCost) AS TotInsCost
FROM vwPayroll
WHERE Dependants = #NoDependants
GROUP BY EmpName
You see, that the only column which has not got any aggregation function is the EmpName...
And the last one - again stated by JamesZ already is the missing underscore in the function's name OBJECT ID:
IF OBJECT_ID('TempEmpData') IS NOT NULL
In your code T-SQL is searching for the meaning of "object" and for a function called "ID"... (The same with IF OBJECT ID('TempWork') IS NOT NULL)
And one last point: On SO it is highly advised to create one question per issue. This question should've been at least parted in two separate questions. Just think of future readers searching for similar problems...
EDIT Ups, there was even one more...
Your last error message points to some code where I do not understand what you really want to achieve... Are you creating a trigger from within the trigger? Might be, the MERGE statement was the better approach for your needs anyway...

Related

How to create schema binding and index on view from other server?

I have tried creating a view with the help of schema binding and indexing which is referring from other server table. But sql thrown some error for the below query .
create VIEW [dbo].[Vxyz]
with schemabinding
AS
SELECT
ELID,USECOUNT,LASTUPDATE,TYPE,CODENE,CASNUE,NAME_ENG,ISGROUP,CHGROUP,DLink
IDE,LOCKBY,PhyApB,BUILDNO,PMNNumE,EINECE
FROM IADL.dbo.tblxyz
GO
create unique clustered index IDX_xyz on [dbo].
[Vxyz](ELID)
Found below error
Msg 4512, Level 16, State 3, Procedure IADL.dbo.tblxyz, Line 3 [Batch Start Line 11]
Cannot schema bind view '[dbo].[Vxyz]' because name 'IADL.dbo.tblxyz' is invalid for schema binding. Names must be in two-part format
and an object cannot reference itself.
Msg 1939, Level 16, State 1, Line 17
Cannot create index on view '[dbo].[Vxyz]' because the view is not schema bound.
select distinct
ISNULL(A.elid, B.elid) ElementID,
CASE when A.elid is null and B.elid is not null then 'Missing ElementID :'+
B.elid+' in Mainproductsall table' when A.elid is not null
and B.elid is null then 'Missing ElementID :'+ A.elid+' in Genproductsall table' Else 'OK'
end Datastatus
into ABC
from [dbo].[Vxyz] As A
full outer join [dbo].[Vxyzwa] as B on A.elid = B.elid
where A.elid is null or B.elid is null
Each from from above query is view . As per my first query above which is referring from other server. so i want to optimize and i am trying to create index.
If you check official documentation, you will see that it is stated as follows
All referenced objects must be in the same database.
So you cannot refer a base table from an other database.
This means, for all referenced current database objects should be referenced with their schema name and object name.

Msg 4104, Level 16, State 1, Line 4 The multi-part identifier "DM_AG_BIZ.SC.WEBN_X86_BR_BILLDOC.Bill_Doc" could not be bound

I created this query to fill in the columns RPS & Nota_Fiscal from table ZOH_BLS08_IDL.ID_NFUM & ZPREFNO respectively, but I get an "could not be bound" error.
insert into [DM_AG_BIZ].[SC].[WEBN_X86_BR_BILLDOC] ([RPS], [Nota_Fiscal])
select [ID_NFNUM], [ZPREFNO]
from [DM_AG_IT].[dbo].[ZOH_BLS08_IDL]
where [DM_AG_BIZ].[SC].[WEBN_X86_BR_BILLDOC].[Bill_Doc] = [DM_AG_IT].[dbo].[ZOH_BLS08_IDL].[BILL_NUM]
-- Switch to target database context
USE [DM_AG_BIZ];
GO
-- remove database qualifier on target table
-- Also, remove brackets since not required here
INSERT INTO SC.WEBN_X86_BR_BILLDOC (RPS, Nota_Fiscal)
-- use 2-part column names
SELECT src.ID_NFNUM, src.ZPREFNO
-- alias the source table
FROM [DM_AG_IT].[dbo].[ZOH_BLS08_IDL] src
-- join to the target table, and alias that as well
JOIN SC.WEBN_X86_BR_BILLDOC tgt
ON src.Bill_Doc = tgt.BILL_NUM

CASE STATEMENT for create view in SQL Server 2008

I have a create view query and I want to check if it does not exist yet, then create view. I tried to create like this:
CASE WHEN IS NOT EXISTS vw_Delays
THEN
VIEW vw_Delays AS
SELECT RD_RfileID_fk_ind, SUM(DATEDIFF(day, RD_Startdate, RD_EndDate)) AS delays FROM dbo.t_RfDelay
GROUP BY RD_RfileID_fk_ind
END
but it returns these errors:
Msg 156, Level 15, State 1, Line 1
Incorrect syntax near the keyword 'CASE'.
Msg 102, Level 15, State 1, Line 6
Incorrect syntax near 'END'.
How to solve this? Please can anyone help me to fix this ?
You need to use this code to check for the view's existence:
IF NOT EXISTS (SELECT * FROM sys.views WHERE Name = N'vw_Delays')
.....
The next obstacle you'll encounter is the fact that the CREATE VIEW statement must be the first of a SQL batch - so you cannot have it right after the existence check.
What I usually do is the opposite:
check if the view does exist
and if so - drop the existing view
then create the view from scratch
and I use this code for this setup:
IF EXISTS (SELECT * FROM sys.views WHERE Name = N'vw_Delays')
DROP VIEW dbo.vw_Delays;
GO
CREATE VIEW dbo.vw_Delays
AS
SELECT
RD_RfileID_fk_ind,
SUM(DATEDIFF(day, RD_Startdate, RD_EndDate)) AS delays
FROM
dbo.t_RfDelay
GROUP BY
RD_RfileID_fk_ind

Create Table As With

Im writing sql query and i have issue which i cannot fix.
I'm trying this:
CREATE TABLE a
AS
WITH cteCandidates (Miejscowosc, Ulica, NrDomu, KodPocztowy)
AS
(
SELECT Miejscowosc, Ulica, NrDomu, KodPocztowy
FROM Gimnazja
INTERSECT
SELECT Miejscowosc, Ulica, NrDomu, KodPocztowy
FROM SzkolyPodstawowe
)
Select
e.Lp as 'Gimnazja',
s.Lp as 'Szkoly Podstawowe'
FROM
Gimnazja AS e
INNER JOIN cteCandidates AS c
ON e.Miejscowosc = c.Miejscowosc AND e.Ulica = c.Ulica AND e.NrDomu = c.NrDomu AND e.KodPocztowy = c.KodPocztowy
INNER JOIN SzkolyPodstawowe s
ON s.Miejscowosc = e.Miejscowosc AND s.Ulica = e.Ulica AND s.NrDomu = e.NrDomu AND s.KodPocztowy = e.KodPocztowy
Order By 'Gimnazja'
And errors which i get:
Msg 156, Level 15, State 1, Line 2
Incorrect syntax near the keyword 'AS'.
Msg 319, Level 15, State 1, Line 3
Incorrect syntax near the keyword 'with'. If this statement is a common table expression, an xmlnamespaces clause or a change tracking context clause, the previous statement must be terminated with a semicolon.
And i don't know why. I think that my query is proper but clearly not, and i don't understand why.
Perhaps you want:
WITH cteCandidates (...)
SELECT
e.Lp as 'Gimnazja',
s.Lp as 'Szkoly Podstawowe'
INTO a -- < -- table created here
FROM
Gimnazja AS e
INNER JOIN ...;
CREATE TABLE is used to define a table schema. The WITH keyword is used to define a CTE retrieval of data. These are two completely different operations.
If you need a table within your SQL look at http://msdn.microsoft.com/en-us/library/ms174979.aspx to see the syntax for defining it. You then may populate it with INSERT but that's highly unlikely to be from a CTE ( see below)
Usually with CTEs you don't need to insert the data into a table; in the statement immediately after it you can just use the data retrieved as the table has been temporarily defined and populated for you automatically.
A CTE can be used to define a VIEW - see Create view based on hierarchy / used of CTE for an example
Are you trying to create a view? Then it'd work...

TSQL to insert an ascending value

I am running some SQL that identifies records which need to be marked for deletion and to insert a value into those records. This value must be changed to render the record useless and each record must be changed to a unique value because of a database constraint.
UPDATE Users
SET Username = 'Deleted' + (ISNULL(
Cast(SELECT RIGHT(MAX(Username),1)
FROM Users WHERE Username LIKE 'Deleted%') AS INT)
,0) + 1
FROM Users a LEFT OUTER JOIN #ADUSERS b ON
a.Username = 'AVSOMPOL\' + b.sAMAccountName
WHERE (b.sAMAccountName is NULL
AND a.Username LIKE 'AVSOMPOL%') OR b.userAccountControl = 514
This is the important bit:
SET Username = 'Deleted' + (ISNULL(
Cast(SELECT RIGHT(MAX(Username),1)
FROM Users WHERE Username LIKE 'Deleted%') AS INT)
,0) + 1
What I've tried to do is have deleted records have their Username field set to 'Deletedxxx'. The ISNULL is needed because there may be no records matching the SELECT RIGHT(MAX(Username),1) FROM Users WHERE Username LIKE 'Deleted%' statement and this will return NULL.
I get a syntax error when trying to parse this (Msg 156, Level 15, State 1, Line 2
Incorrect syntax near the keyword 'SELECT'.
Msg 102, Level 15, State 1, Line 2
Incorrect syntax near ')'.
I'm sure there must be a better way to go about this, any ideas?
If your Users table already has an integer PK column, you can simply use this column to generate 'Deleted'+PK usernames.
Btw, would the SELECT RIGHT(MAX(Username),1) not fail after 10 users? Better to use SUBSTRING().
Is it strictly necessary to use incremental 'xxx' values? Couldn't you just use random values?
SET Username = Username + '_deleted_' + CAST(NEWID() AS char(36))
Additionally, it might be a bad idea to overwrite the login completely. Given that you disable the record, not delete it entirely, I assume that you need it for audit purposes or smth. like that. In this case, records with IDs like 'Deleted1234' might be too anonymous.
I suspect this would work better as a multi-step SQL statement, but I'm unsure if that's reasonable.
The error you're seeing is because you're trying to concatenate an int to a string, you're also adding 1. Your order of operations is all screwy in that set statement. This does what you're asking, but it will fail the minute you get more than 9 deleted entries.
SELECT 'DELETED' + CAST(
ISNULL(
CAST(
SELECT RIGHT(MAX(Username),1)
FROM #Users WHERE username LIKE 'DELETED%')
AS INT)
, 0) + 1 )
AS VARCHAR(3))
edit: sorry for the horrible formatting. Couldn't figure out how to make it readable.

Resources