How to create default constraint on the table of Firebird to assign auto-generated UUID value - sql

I am trying to define a table with a column type of UUID (CHAR(16) CHARACTER SET OCTETS). After reading through the Firebird 3.0 Developer's Guide, I found only context-variables/simple expression/constant are supported. I would like to know if there is a way to define a default constraint on a table to call GEN_UUID() to assign UUID for insertion?

You cannot do this with a DEFAULT clause, as that only allows literals and a select number of what the Firebird documentation refers to as 'context variables'.
To do what you want, you need to create a before insert trigger to generate the value. Something like this:
create trigger bi_yourtable before insert on yourtable
as
begin
new.uuid_column = gen_uuid();
end
Or, if you don't want unconditional generation of the UUID:
create trigger bi_yourtable before insert on yourtable
as
begin
if (new.uuid_column is null) then
begin
new.uuid_column = gen_uuid();
end
end

Related

using user-defined function for constraint in SQL

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;

Snowflake: Trying to make a column to use as default the value from a sequence

So, I have something like this:
CREATE OR REPLACE TABLE TABLE_NAME (
ID NUMBER(38, 0) NOT NULL,
/* OTher elements */
)
With some values already (manually) inserted. I need to update this table so, for future inserts, the value of ID is taken from a sequence I just created:
CREATE OR REPLACE SEQUENCE S_TABLE_NAME_ID
START WITH 451;
For what I've seen in the documentation and in several forums, the syntax should be like this:
ALTER TABLE TABLE_NAME ALTER ID SET DEFAULT S_TABLE_NAME_ID.NEXTVAL;
But when I try to execute it, I get the following error message:
SQL Error [2] [0A000]: Unsupported feature 'Alter Column Set Default'.
Am I missing here something?
from Snowflake Doc (https://docs.snowflake.com/en/sql-reference/sql/alter-table-column.html):
"To change the default sequence for a column, the column must already
have a default sequence. You cannot use the command ALTER TABLE ...
SET DEFAULT <seq_name> to add a sequence to a column that does not
already have a sequence."
So I guess you have to set the sequence as column default when creating the table.

Checking some columns for specific values before insert/update using a trigger

I have a database FOO with several columns, among those I have one column "Url". I need to write a trigger before insert/update that will check the Url columns whether the newer value matches any existing values, i.e. "hello" except some predefined value. That means if "hello" is inserted or updated multiple times no error will happen otherwise it will check for duplicity. And if it finds some aborts the insertion update. This will also return some code so that my script calling for the insertion/update will know a failure has occurred. I know there might be other workarounds but I will need to have it this way. I am pretty new to SQL.
Foo {
Url
}
Here is the algorithm
Before update insert
if new value of Url is not "hello1" o "hello 2"
check if new value of Url already exists in Foo.Url if so abort otherwise allow update/insert
return something if aborted/success
try something like this.. you'll need to index your table..
IF EXISTS(SELECT URL FROM Foo.Url)
BEGIN
SELECT 'URL Exists Already'
END
ELSE
BEGIN
INSERT/UPDATE
END
A unique constraint wouldn't do what you want but you could create an instead of trigger with content something like as:
Create TRIGGER [dbo].[Trig_Insert_XXX]
ON [dbo].[XXX]
INSTEAD OF INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO xxx ([url], field1, field2, fieldN)
SELECT [url], field1, field2, fieldN
FROM inserted i
WHERE i.url = 'hello' OR NOT EXISTS (SELECT * FROM xxx t2 WHERE t2.url = i.url);
END;
I suppose you're looking for a UNIQUE constraint & a CHECK constraint as
CREATE TABLE Foo(
Url VARCHAR(250) NOT NULL,
CONSTRAINT UQ_Url UNIQUE(Url),
CONSTRAINT CHK_Url CHECK (Url NOT IN ('hello1', 'hello2'))
);
See how it's working online.
If you are using SQL Server 2008 or newer version you can use MERGE as well, the syntax is like the following :
MERGE [TableName] AS TARGET
USING ( SELECT #UrlName ) AS SOURCE (UrlName) ON SOURCE.UrlName = TARGET.UrlName
WHEN MATCHED THEN
UPDATE SET ...
WHEN NOT MATCHED THEN INSERT ()
VALUES ();

Create a new column based on other columns

I've managed to create the following column in a new table:
CREATE TABLE t_issue_dates as
SELECT issue_d,
cast(substr(issue_d,5,4) as numeric) as issue_year
FROM myDB
(The code recodes a year-month variable to a year-only variable)
However, i can't add this variable to my existing table "myDB". I've tried using the:
ALTER TABLE myDB ADD v_year - command, but i can't manage to get it right.
Does anyone have an idea how i add the above variable to the "original" table myDB?
Thank you!
First, many databases support computed or generated columns. That means that you can add a virtual column to the database by doing:
alter table t_issue_dates add issue_year as (cast(substr(issue_d, 5, 4) as numeric));
I recommend this approach because issue_year is always up-to-date.
Second, you can do this as an actual column, but the value can get out-of-date and needs to be re-calculated for each inserted/updated row:
alter table t_issue_dates add issue_year numeric;
update t_issue_dates
set issue_year = cast(substr(issue_d, 5, 4) as numeric);
For the record, I would use int rather than numeric.
Assuming you are using MSSQL. It would be worth of reading documentation or a simple google on how to insert
Adding column :
Alter table t_issue_dates
Add V_year Int
Next step: This will only insert data for this particular column.
Insert into t_issue_dates (v_year)
SELECT
cast(substr(issue_d,5,4) as numeric)
FROM myDB

Creating a sequence on an existing table

How can I create a sequence on a table so that it goes from 0 -> Max value?
I've tried using the following SQL code, but it does not insert any values into the table that I am using:
CREATE SEQUENCE rid_seq;
ALTER TABLE test ADD COLUMN rid INTEGER;
ALTER TABLE test ALTER COLUMN rid SET DEFAULT nextval('rid_seq');
The table I am trying to insert the sequence in is the output from another query. I can't figure out if it makes more sense to add the sequence during this initial query, or to add the sequence to the table after the query is performed.
Set the default value when you add the new column:
create sequence rid_seq;
alter table test add column rid integer default nextval('rid_seq');
Altering the default value for existing columns does not change existing data because the database has no way of knowing which values should be changed; there is no "this column has the default value" flag on column values, there's just the default value (originally NULL since you didn't specify anything else) and the current value (also NULL) but way to tell the difference between "NULL because it is the default" and "NULL because it was explicitly set to NULL". So, when you do it in two steps:
Add column.
Change default value.
PostgreSQL won't apply the default value to the column you just added. However, if you add the column and supply the default value at the same time then PostgreSQL does know which rows have the default value (all of them) so it can supply values as the column is added.
By the way, you probably want a NOT NULL on that column too:
create sequence rid_seq;
alter table test add column rid integer not null default nextval('rid_seq');
And, as a_horse_with_no_name notes, if you only intend to use rid_seq for your test.rid column then you might want to set its owner column to test.rid so that the sequence will be dropped if the column is removed:
alter sequence rid_seq owned by test.rid;
In PostgreSQL:
UPDATE your_table SET your_column = nextval('your_sequence')
WHERE your_column IS NULL;
I'm not fluent in postgresql so I'm not familiar with the "CREATE SEQUENCE" statement. I would think, though, that you're adding the column definition correctly. However, adding the column doesn't automatically insert data for existing rows. A DEFAULT constraint is for new rows. Try adding something like this afterwards to populate data on the existing rows.
DECLARE #i Int
SET #i = 0
SET ROWCOUNT 1
WHILE EXISTS (SELECT 1 FROM test WHERE rid IS NULL) BEGIN
UPDATE test SET rid = #i WHERE rid IS NULL
END
SET ROWCOUNT 0