I am trying to add a check constraint to my table in SQL database so that user can only enter the work_group in the column that is in the 'approved list' - dbo.work_groups.
I've read a few forums and created the following table, user defined function and constraint.
dbo.work_groups is populated with the list of work groups, i.e. 'Admin','Accountant', 'Engineer'.
When I enter the above work groups into dbo.test it accepts them. But it also accepts any other values.
How can I limit the constraint only to those work groups that are listed in the dbo.work_groups.
What have I done wrong?
Thanks.
-----test table
CREATE TABLE [dbo].[test]
([testname] nvarchar NOT NULL)
-----user defined function
CREATE FUNCTION [dbo].[check_work_group](#testname NVARCHAR(50))
RETURNS NVARCHAR(50)
AS
BEGIN
RETURN (SELECT work_group FROM [dbo].[work_groups] WHERE work_group=#testname)
END;
-----constraint
ALTER TABLE test ADD constraint CK_testname
CHECK (testname=dbo.check_work_group(testname));
I think the issue with the function. When there is no record in the work_groups table for a given parameter value, it is returning null, which is causing the issue. One way to solve it is by forcing the function to return a value that does not exist in work_groups table ('-1' in the example below) when no record is found for the given parameter value.
CREATE FUNCTION [dbo].[check_work_group](#testname NVARCHAR(50))
RETURNS NVARCHAR(50) AS
BEGIN
RETURN COALESCE((SELECT work_group FROM [dbo].[work_groups] WHERE work_group=#testname), '-1');
END;
Related
I need to get a userstamp into a table and have not managed to figure out how the GENERATED FOR EACH ROW ON UPDATE AS statement works with the SESSION_USER variable in DB2 10.5 (LUW).
Managed to get an implementation working using a function which has a fake variable for forcing the evaluation in update statements:
CREATE OR REPLACE FUNCTION XXX.CURRENT_USER( tmp varchar(128))
SPECIFIC xxx.XXX_CURRENT_USER
RETURNS VARCHAR(128)
CONTAINS SQL DETERMINISTIC NO EXTERNAL ACTION
BEGIN
RETURN session_user ;
END
GO
CREATE TABLE xxx (
i INTEGER,
t VARCHAR(128) GENERATED ALWAYS AS (XXX.CURRENT_USER(i))
)
However, would be nice have less "hacky" implementation for a basic thing like this.
For the time stamps there is that "FOR EACH ROW ON UPDATE AS ROW CHANGE TIMESTAMP" statement but no equivalent for other register variables it seems.
Help is very much appreciated
Does this work?
CREATE TABLE xxx (
i INTEGER,
t VARCHAR(128) WITH DEFAULT session_user
);
I don't have DB2 on hand to check, but this is very similar to the syntax used in other databases (although the more typical syntax does not use WITH).
I am relatively newbie with SQL Server, and I have some experience and practices from Oracle & PostgreSQL which i want to use in the SQL Server.
I need to create function which takes fields values for new row in the table and which also returning autogenerated ID value of the new record.
First of all I am faced with the fact that the functions in SQL Server can not change data in the tables. The second my discovery was that is the procedures in SQL Server can return values through return #result construction.
I investigate output mechanism of the DML queries, but they returns not scalar but table results.
Be patient and let me more clear. There is PostgreSQL function which doing what I want:
Table creation script:
create table foobar
(
foo bigint not null default nextval('s_foobar'::regclass),
bar character varying(16),
constraint pk_foobar primary key (foo)
);
and function script:
create or replace function f_foobar_insert(p_bar character varying)
returns integer as
$body$declare
result integer;
begin
insert into foobar(bar) values (p_bar) returning foo into result;
return result;
end;$body$ language plpgsql;
Is there any possibility to make something like this in SQL Server in the same way?
In SQL Server, the table creation would be:
create table foobar
(
foo bigint not null identity primary key,
bar varchar(16)
);
The following is one way in SQL Server to get the functionality:
insert into foobar(bar) select 'value';
select ##identity;
This is not really the preferred way. You should really use the output clause:
declare #t table (foo bigint);
insert into foobar(bar)
output inserted.foo into #t
select 'value';
select foo from #t;
You can wrap this in a stored procedure if you like, but it doesn't seem necessary, and stored procedures have different semantics from functions.
I want to do the following
ALTER TABLE runs ADD COLUMN userId bigint NOT NULL DEFAULT (SELECT id FROM users WHERE email = 'admin#example.com');
but it keeps giving me syntax error. How could I do this guys?
Any help is highly appreciated. ;)
Create a function to get the id from the table users with email as an arg.
CREATE OR REPLACE FUNCTION id_in_users(iemail varchar)
RETURNS int LANGUAGE SQL AS $$
SELECT id FROM users WHERE email = email;
$$;
And alter the table
ALTER TABLE runs ADD COLUMN userId bigint NOT NULL DEFAULT
id_in_users('admin#example.com');
SQL FIDDLE(DEMO)
You can't do that on DEFAULT. However you could use a trigger before insert checking if there is a NULL value.
You can check the PostgreSQL Trigger Documentation here
I want a stored procedure to return the primary key of the new record after it gets executed. I think it will be returned by OUT parameter in the procedure. But how to select the newly inserted row ID ? I don't want to use select MAX(row_id) as it is a multi user environment.
Any procedure sample will be appreciated.
My platform is ISeries DB2 V5 R4. Thanks.
Edit
The row id Column is not an identity column. It uses a sequence for the key which gets generated via a trigger before insert on table.
Edit
Here is what I am trying to do
Begin Stored procedure
Insert into Employees;
(row id gets automatically generated by trigger)
Return row id ;
I want to avoid a select in returning row id.
just set the out parameter to the column that contains the PK.
CREATE PROCEDURE DB2TBL.DO_STUFF (IN Param1 INT, IN Param2 CHAR(32),OUT Param3 INT)
/* Param1 is primary key */
LANGUAGE SQL
P1: BEGIN
DECLARE OUTPARAM INT;
/* Do the stored procedure */
SET OUTPARAM = Param1;
--UPDATED---
Hi Popo,
First off could you give more detail on what you mean when you say the rowid is assigned by a trigger?
If you had a real identity column you would use the IDENTITY_VAL_LOCAL() function like this right after the INSERT: SELECT IDENTITY_VAL_LOCAL() INTO myrowid FROM SYSIBM.SYSDUMMY1; I'm not 100% on that syntax because I generally use embedded SQL and it works differently there so you might have to play with it. IBM documentation is at http://publib.boulder.ibm.com/infocenter/iseries/v6r1m0/index.jsp?topic=/db2/rbafzscaidentity.htm.
However since you are doing something more complicated, I think this alternate method might work. You'll need to re-format your INSERT to be wrapped in a SELECT.
SELECT myrowid
INTO myrowid
FROM FINAL TABLE (
INSERT INTO myfile (myrowid, other_stuff) VALUES (default, 'blah')
)
You'll need to adjust for the proper field names and so on but I think this will do the trick. There's not much documentation but if you want to see it go to http://publib.boulder.ibm.com/infocenter/iseries/v6r1m0/index.jsp?topic=/db2/rbafzbackup.htm and scroll all the way down to the bottom of the page.
Cheers
CREATE PROCEDURE ASF_InsertNewAuthorRequest
(IN #REQUESTTYPE CHAR(1), IN #UserID VARCHAR(18), IN #DATECREATED TIMESTAMP, IN #REQUESTSTATUS CHAR(1))
LANGUAGE SQL
DYNAMIC RESULT SETS 1
P1: BEGIN
DECLARE cursor1 CURSOR WITH RETURN for
SELECT IDENTITY_VAL_LOCAL FROM SYSIBM.SYSDUMMY1;
INSERT INTO AFS_REQUEST
( REQUESTTYPE, "UserID", DATECREATED, REQUESTSTATUS )
VALUES
( #REQUESTTYPE, #UserID, #DATECREATED, #REQUESTSTATUS );
OPEN cursor1;
END P1
INSERT INTO [User] (columns)
OUTPUT inserted.userId
VALUES (#values)
This will return the newly created userId column value... very simple.
First of all, thank you guys. You always know how to direct me when I can't even find the words to explain what the heck I'm trying to do.
The default values of the columns on a couple of my tables need to be equal the result of some complicated calculations on other columns in other tables. My first thought is to simply have the column default value equal the result of a stored procedure. I would also have one or more of the parameters pulled from the columns in the calling table.
I don't know the syntax of how to do it though, and any time the word "stored" and "procedure" land next to each other in google I'm flooded with info on Parameter default values and nothing relating to what I actually want.
Half of that was more of a vent than a question...any ideas though? And plz plz don't say "Well, you could use an On-Insert Trigger to..."
You can't have the default be the result of a stored procedure, it has to be a function. If you can convert the procedure into a function, then you can use that function. If you cannot, then you must use a trigger.
You would have to convert that stored procedure to a user-defined function. There are different types of UDF's - the one you're looking at would be the scalar UDF - returning a single value.
So for instance you could create a function like this:
CREATE FUNCTION dbo.YourDefaultFunction(#Input1 INT, #Input2 VARCHAR(10))
RETURNS VARCHAR(100)
AS BEGIN
DECLARE #Result VARCHAR(100)
SET #Result = #Input2 + ' - giving: ' + CAST(#Input1 AS VARCHAR(5))
RETURN #Result
END
Of course, yours would be a lot more complicated :-)
Once you've done that, you can define this to be the default for a column of type VARCHAR(100) - either directly when declaring the table, or later on via an ALTER TABLE statement:
CREATE TABLE dbo.YourTable(.......
SomeColumn VARCHAR(100)
CONSTRAINT DF_YourTable_SomeColumn
DEFAULT (dbo.YourDefaultFunction(417, 'Test')),
.....)
or :
ALTER TABLE dbo.YourTable
ADD CONSTRAINT DF_YourTable_SomeColumn
DEFAULT (dbo.YourDefaultFunction(4711, 'Test2'))
FOR SomeColumn
Unfortunately, you cannot pass other columns as parameters to your function when defining it as a default value for a column.
Does that help??