问题
Using PostgreSQL, how do I manage a sequence (auto incremented Integer id) for the following scenario-
Table named 'businesses' which has 'id' and some more columns.
Table named 'users' which has:
a composite primary key, composed of a 'business_id', and an 'id', and have the 'id' reset it's counting for each 'business_id' when I insert now rows.
a simple column 'name'.
something like having a separate sequence per business.
Example
When I run the following queries:
insert into users (business_id, name) values (1, 'a')
insert into users (business_id, name) values (2, 'b')
insert into users (business_id, name) values (1, 'c')
I want to end up with the following 'users' table:
business_id, id, name
1, 1, 'a'
1, 2, 'c'
2, 1, 'b'
回答1:
You cannot use Sequences if you can´t predict how many (maximum) Users will be related to one businesses (and even if you can, I would not advise the use of increment that way).
If you use Postgres >=9 you can use WITH to avoid the max query, by placing the counter as a column of the master table (or create a new table that holds a pair business_id(PK),next_id if you can´t change the Businesses table).
Add the column next_id:
ALTER TABLE Businesses ADD COLUMN next_id bigint;
//update current rows with default value
ALTER TABLE Businesses ALTER COLUMN next_id SET DEFAULT 0;
ALTER TABLE Businesses ALTER COLUMN next_id SET NOT NULL;
To insert into Users, use the following single SQL statement, that returns the new id as a result.
With X as (
Update Businesses
set next_id=next_id+1
where id=:param_business_id
Returning next_id)
Insert into Users (business_id,id,name)
Select :param_business_id, X.next_id ,:param_name
From X
Returning id
This will insert the first id as "1", because (the first) returning clause returns the updated value. Or if you use a separate table that holds the ids, just replace the "Update Businesses" to the "Update MY_ID_TABLE". Notice that this solution is not vanilla SQL.
回答2:
INSERT INTO [users]
(business_id, id)
FROM
(
SELECT
ID - (SELECT MIN(ID) FROM [users] WHERE business_ID = B.ID) AS business_id
,(SELECT MAX(ID)+1 FROM [users] WHERE business_ID = B.ID) AS ID
FROM [businesses] B
)
if you link this to the new entries you are adding, it should provide the composite key
New Update:
INSERT INTO [users]
(business_id, id, name)
VALUES
(
3
,ISNULL((SELECT MAX(ID)+1 FROM [users] WHERE business_ID = 3),1) AS ID
,'d'
)
来源:https://stackoverflow.com/questions/19060469/sequences-with-composite-primary-key