Postgres Sequence is generating negative values as primary keys - database

I have a table which uses a sequence to auto-generate the Primary Key when inserting a record. However, the sequence is generating negative values.
How do I enforce that only positive values are generated and is there a way to generated the ids randomly (especially a varchar type)
questionnaries.sql #
CREATE TABLE public.questionnaries
(
id integer NOT NULL DEFAULT nextval('questionnaries_id_seq'::regclass),
personname character varying(255) NOT NULL,
question character varying(255) NOT NULL,
response character varying(255) NOT NULL,
CONSTRAINT questionnaries_pkey PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
);
ALTER TABLE public.questionnaries
OWNER TO postgres;
questionnaries_id_seq
CREATE SEQUENCE public.questionnaries_id_seq
INCREMENT 1
MINVALUE 1
MAXVALUE 9223372036854775807
START 6
CACHE 1;
ALTER TABLE public.questionnaries_id_seq
OWNER TO postgres;

First Create a Sequence like below .Whichever number you wanna start give that for e.g. 0 or 100.
CREATE SEQUENCE questionnaries_id_seq START 0;
you can query also
SELECT nextval('questionnaries_id_seq');

The Sequence generate the negative value in two scenarios,
1# you have created the sequence and specify the INCREMENT BY values in a negative("-1").
2# The sequence INCREMENT BY is in positive and correct form but, sequence reached to their MAX value and that's the reason it started generating the MIN value of the sequence.
There will two solutions for this,
Use the "NO MAXVALUE" with "NO CYCLE" parameter of the sequence as specified below.
CREATE SEQUENCE <>
NO MAXVALUE
START WITH 0
INCREMENT BY 1
NO CYCLE;
Use the "SERIAL" to generate the numerical values by PostgreSQL.
CREATE TABLE table_name (
column_1 integer PRIMARY KEY DEFAULT nextval('serial'),
column_2 varchar(40) NOT NULL
);

Related

Update table with random DECIMAL number within a range (SQL Server)

I want to update the column ItemValue of table Items with a decimal value generated randomly within 1 and 100 (a different value for each row). Each value should have two (random) digits.
CREATE TABLE Items
(
ItemID int IDENTITY(1,1) NOT NULL,
ItemValue decimal(13, 4) NULL,
CONSTRAINT PK_Items PRIMARY KEY CLUSTERED (ItemID ASC)
)
INSERT INTO Items(ItemValue) VALUES (0)
INSERT INTO Items(ItemValue) VALUES (0)
INSERT INTO Items(ItemValue) VALUES (0)
INSERT INTO Items(ItemValue) VALUES (0)
-- Now, I want to update the table
You can use RAND to generate random number. But there is one problem - RAND is executed only once per query, so all your rows will contain same random value. You can use CHECKSUM(NEWID()) to make it random per row, like this
UPDATE items
SET itemValue = ROUND(RAND(CHECKSUM(NEWID())) * (100), 2)
You could use this snippet to generate random decimal values:
CONVERT( DECIMAL(13, 4), 10 + (30-10)*RAND(CHECKSUM(NEWID()))
This will generate random decimal numbers between 10 and 30.

Ensure foreign key of a foreign key matches a base foreign key

Basically let's say I have a "Business" that owns postal codes that it services. Let's also suppose I have another relational table that sets up fees.
CREATE TABLE [dbo].[BusinessPostalCodes]
(
[BusinessPostalCodeId] INT IDENTITY (1, 1) NOT NULL,
[BusinessId] INT NOT NULL,
[PostalCode] VARCHAR (10) NOT NULL
)
CREATE TABLE [dbo].[BusinessPostalCodeFees]
(
[BusinessId] INT NOT NULL,
[BusinessProfileFeeTypeId] INT NOT NULL,
[BusinessPostalCodeId] INT NOT NULL,
[Fee] SMALLMONEY NULL
)
I want to know if it's possible to set up a foreign key (or something) on BusinessPostalCodeFees that ensures that the related BusinessId of BusinessPostalCodes is the same as the BusinessId of BusinessPostalCodeFees.
I realize that I can remove BusinessId entirely, but I would much rather keep this column and have a way of guaranteeing they will be the same. Is there anything I can do?
It sounds like (and correct me if I'm wrong) that you're trying to make sure that any entry into BusinessPostalCodeFees' BusinessId and BusinessPostalCodeId columns match an entry in the BusinessPostalCodes table. If that's the case, then yes, you can definitely have a foreign key that references a compound primary key.
However, if you need to keep the BusinessId, I'd recommend normalizing your tables a step further than you have. You'll end up with duplicate data as-is.
On a side note, I would recommend you don't use the money data types in SQL: See here.
In the end, Jeffrey's solution didn't quite work for my particular situation. Both columns in the relation have to be unique (like a composite key). Turns out the answer here (for me) is a Checked Constraint.
Create a function that you want to have the constraint pass or fail:
CREATE FUNCTION [dbo].[MatchingBusinessIdPostalCodeAndProfileFeeType]
(
#BusinessId int,
#BusinessPostalCodeId int,
#BusinessProfileFeeTypeId int
)
RETURNS BIT
AS
BEGIN
-- This works because BusinessPostalCodeId is a unique Id.
-- If businessId doesn't match, its filtered out.
DECLARE #pcCount AS INT
SET #pcCount = (SELECT COUNT(*)
FROM BusinessPostalCodes
WHERE BusinessPostalCodeId = #BusinessPostalCodeId AND
BusinessId = #BusinessId)
-- This works because BusinessProfileFeeTypeId is a unique Id.
-- If businessId doesn't match, its filtered out.
DECLARE #ftCount AS INT
SET #ftCount = (SELECT COUNT(*)
FROM BusinessProfileFeeTypes
WHERE BusinessProfileFeeTypeId = #BusinessProfileFeeTypeId AND
BusinessId = #BusinessId)
-- Both should have only one record
BEGIN IF (#pcCount = 1 AND #ftCount = 1)
RETURN 1
END
RETURN 0
END
Then just add it to your table:
CONSTRAINT [CK_BusinessPostalCodeFees_MatchingBusinessIdPostalCodeAndProfileFeeType]
CHECK (dbo.MatchingBusinessIdPostalCodeAndProfileFeeType(
BusinessId,
BusinessPostalCodeId,
BusinessProfileFeeTypeId) = 1)

Trailing spaces allowed in foreign keys

Issue: SQL Server allows trailing spaces to be added to a foreign key!
This behaviour of course leads to various unwanted behaviour in the application. How can this be stopped?
Example: Two tables in a 1:n relationship:
create table products
(
pid nvarchar(20) primary key
;)
create table sales
(
pid nvarchar(20) references products(pid),
units int
);
Now insert primary key 'A':
insert into products (pid) values ('A');
Now insert foreign keys:
-- 'A' is accepted, as expected:
insert into sales (pid, units) values ('A', 23);
-- 'B' is declined, as expected:
insert into sales (pid, units) values ('B', 12);
-- 'A ' (with a trailing space)
-- This is ACCEPTED, but of course this is NOT EXPECTED !!
insert into sales (pid, units) values ('A ', 12);
A second issue is that this is really hard to detect since :
select pid from sales group by pid
returns only one value: A in your example
Here is a trick to help detect the issue:
select pid from sales group by binary(pid)
This returns 2 rows: A and A (with trailing space)
Cheers,
If you just plain don't want to allow trailing spaces:
create table sales
(
pid nvarchar(20) references products(pid),
units int,
constraint CK_sales_pid CHECK (RIGHT(pid,1) <> ' ')
);
Otherwise, you need to realise that this is not just a single "unexpected" situation. The SQL Standard says that when there are two strings with unequal lengths, the shorter string is first padded with spaces to make the lengths equal, before comparisons occur.

How to make SQL Server table primary key auto increment with some characters

I have a table like this :
create table ReceptionR1
(
numOrdre char(20) not null,
dateDepot datetime null,
...
)
I want to increment my id field (numOrdre) like '225/2015','226/2015',...,'1/2016' etc. What should I have to do for that?
2015 means the actual year.
Please let me know any possible way.
You really, and I mean Really don't want to do such a thing, especially as your primary key. You better use a simple int identity column for you primary key and add a non nullable create date column of type datetime2 with a default value of sysDateTime().
Create the increment number by year either as a calculated column or by using an instead of insert trigger (if you don't want it to be re-calculated each time). This can be done fairly easy with the use of row_number function.
As everyone else has said - don't use this as your primary key! But you could do the following, if you're on SQL Server 2012 or newer:
-- step 1 - create a sequence
CREATE SEQUENCE dbo.SeqOrderNo AS INT
START WITH 1001 -- start with whatever value you need
INCREMENT BY 1
NO CYCLE
NO CACHE;
-- create your table - use INT IDENTITY as your primary key
CREATE TABLE dbo.ReceptionR1
(
ID INT IDENTITY
CONSTRAINT PK_ReceptionR1 PRIMARY KEY CLUSTERED,
dateDepot DATE NOT NULL,
...
-- add a colum called "SeqNumber" that gets filled from the sequence
SeqNumber INT,
-- you can add a *computed* column here
OrderNo = CAST(YEAR(dateDepot) AS VARCHAR(4)) + '/' + CAST(SeqNumber AS VARCHAR(4))
)
So now, when you insert a row, it has a proper and well defined primary key (ID), and when you fill the SeqNumber with
INSERT INTO dbo.ReceptionR1 (dateDepot, SeqNumber)
VALUES (SYSDATETIME(), NEXT VALUE FOR dbo.SeqOrderNo)
then the SeqNumber column gets the next value for the sequence, and the OrderNo computed column gets filled with 2015/1001, 2015/1002 and so forth.
Now when 2016 comes around, you just reset the sequence back to a starting value:
ALTER SEQUENCE dbo.SeqOrderNo RESTART WITH 1000;
and you're done - the rest of your solution works as before.
If you want to make sure you never accidentally insert a duplicate value, you can even put a unique index on your OrderNo column in your table.
Once more, you cannot use the combo field as your primary key. This solution sort or works on earlier versions of SQL and calculates the new annual YearlySeq counter automatically - but you had better have an index on dateDepot and you might still have issues if there are many, many (100's of thousands) of rows per year.
In short: fight the requirement.
Given
create table dbo.ReceptionR1
(
ReceptionR1ID INT IDENTITY PRIMARY KEY,
YearlySeq INT ,
dateDepot datetime DEFAULT (GETDATE()) ,
somethingElse varchar(99) null,
numOrdre as LTRIM(STR(YearlySeq)) + '/' + CONVERT(CHAR(4),dateDepot,111)
)
GO
CREATE TRIGGER R1Insert on dbo.ReceptionR1 for INSERT
as
UPDATE tt SET YearlySeq = ISNULL(ii.ReceptionR1ID - (SELECT MIN(ReceptionR1ID) FROM dbo.ReceptionR1 xr WHERE DATEPART(year,xr.dateDepot) = DATEPART(year,ii.dateDepot) and xr.ReceptionR1ID <> ii.ReceptionR1ID ),0) + 1
FROM dbo.ReceptionR1 tt
JOIN inserted ii on ii.ReceptionR1ID = tt.ReceptionR1ID
GO
insert into ReceptionR1 (somethingElse) values ('dumb')
insert into ReceptionR1 (somethingElse) values ('requirements')
insert into ReceptionR1 (somethingElse) values ('lead')
insert into ReceptionR1 (somethingElse) values ('to')
insert into ReceptionR1 (somethingElse) values ('big')
insert into ReceptionR1 (somethingElse) values ('problems')
insert into ReceptionR1 (somethingElse) values ('later')
select * from ReceptionR1

Store default sequence number in table without using any variable

I have one table in database which should contain sequence number.
create table SequenceNumber(
number int indentity(1,1) primary key
)
Now I want to store number from 1 to 1448 without setting IDENTITY_INSERT ON/OFF and without counter variable.
I need values from 1 to 1448 in 'number' column
can anyone tell me how can I do it?
yes you can do it as follow
just change the value 1448 as per your need
idea from here : http://www.codeproject.com/Tips/780441/Tricky-SQL-Questions
CREATE TABLE SequenceNumber(
NUMBER BIGINT IDENTITY(1,1) PRIMARY KEY
)
WHILE(1=1)
BEGIN
INSERT INTO SequenceNumber
DEFAULT VALUES
IF EXISTS(SELECT 1 FROM SequenceNumber WHERE NUMBER = 1448)
BREAK
END
SELECT NUMBER FROM SequenceNumber

Resources