Update: This bug has been fixed in PostgreSQL v12 with commit 19781729f78.
The rest of the answer is relevant for older versions.
A serial
column has a sequence that is owned by the column and a DEFAULT
value that gets the net sequence value.
If you try to change that column into an identity column, you’ll get an error that there is already a default value for the column.
Now you must have dropped the default value, but not the sequence that belongs to the serial
column. Then when you converted the column into an identity column, a second sequence owned by the column was created.
Now when you try to insert a row, PostgreSQL tries to find and use the sequence owned by the column, but there are two, hence the error message.
I’d argue that this is a bug in PostgreSQL: in my opinion, it should either have repurposed the existing sequence for the identity column or given you an error that there is already a sequence owned by the column, and you should drop it. I’ll try to get this bug fixed.
Meanwhile, you should manually drop the sequence left behind from the serial
column.
Run the following query:
SELECT d.objid::regclass
FROM pg_depend AS d
JOIN pg_attribute AS a ON d.refobjid = a.attrelid AND
d.refobjsubid = a.attnum
WHERE d.classid = 'pg_class'::regclass
AND d.refclassid = 'pg_class'::regclass
AND d.deptype <> 'i'
AND a.attname = 'patientid'
AND d.refobjid = 'patient'::regclass;
That should give you the name of the sequence left behind from the serial
column. Drop it, and the identity column should behave as desired.
Update: This bug has been fixed in PostgreSQL v12 with commit 19781729f78.
The rest of the answer is relevant for older versions.
A serial
column has a sequence that is owned by the column and a DEFAULT
value that gets the net sequence value.
If you try to change that column into an identity column, you’ll get an error that there is already a default value for the column.
Now you must have dropped the default value, but not the sequence that belongs to the serial
column. Then when you converted the column into an identity column, a second sequence owned by the column was created.
Now when you try to insert a row, PostgreSQL tries to find and use the sequence owned by the column, but there are two, hence the error message.
I’d argue that this is a bug in PostgreSQL: in my opinion, it should either have repurposed the existing sequence for the identity column or given you an error that there is already a sequence owned by the column, and you should drop it. I’ll try to get this bug fixed.
Meanwhile, you should manually drop the sequence left behind from the serial
column.
Run the following query:
SELECT d.objid::regclass
FROM pg_depend AS d
JOIN pg_attribute AS a ON d.refobjid = a.attrelid AND
d.refobjsubid = a.attnum
WHERE d.classid = 'pg_class'::regclass
AND d.refclassid = 'pg_class'::regclass
AND d.deptype <> 'i'
AND a.attname = 'patientid'
AND d.refobjid = 'patient'::regclass;
That should give you the name of the sequence left behind from the serial
column. Drop it, and the identity column should behave as desired.
Я устанавливаю столбец идентификаторов в существующие столбцы таблицы Patient
.
Здесь я хотел бы использовать ВСЕГДА В КАЧЕСТВЕ ИДЕНТИЧНОСТИ .
Поэтому я установил столбец идентификаторов, используя следующую инструкцию (ранее это было serial
):
ALTER TABLE Patient ALTER PatientId
ADD GENERATED ALWAYS AS IDENTITY (START WITH 1);
Для существующей таблицы пациентов у меня всего 5 записей. (patientId
с 1 по 5)
Когда я вставляю новую запись после установки идентификатора, она выдаст ошибку вроде:
more than one owned sequence found
Даже после сброса идентификационной колонки я все равно получаю ту же ошибку.
ALTER TABLE Patient ALTER COLUMN PatientId RESTART WITH 6;
Дайте мне знать, если у вас есть какие-либо решения.
2 ответа
Лучший ответ
Обновление : эта ошибка была исправлена в PostgreSQL версии 12 с помощью commit 19781729f78.
Остальная часть ответа актуальна для более старых версий.
Столбец serial
имеет последовательность, которой владеет столбец, и значение DEFAULT
, которое получает значение чистой последовательности.
Если вы попытаетесь изменить этот столбец в столбец идентификаторов, вы получите сообщение об ошибке, что для столбца уже есть значение по умолчанию.
Теперь вы должны удалить значение по умолчанию, но не последовательность, которая принадлежит столбцу serial
. Затем, когда вы преобразовали столбец в столбец идентификаторов, была создана вторая последовательность, принадлежащая столбцу.
Теперь, когда вы пытаетесь вставить строку, PostgreSQL пытается найти и использовать последовательность , принадлежащую столбцу, но их две, поэтому появляется сообщение об ошибке.
Я бы сказал, что это ошибка в PostgreSQL: по моему мнению, он должен был либо переназначить существующую последовательность для столбца идентификаторов, либо дать вам ошибку, что последовательность уже принадлежит столбцу, и вы должны удалить ее. Я постараюсь исправить эту ошибку.
Тем временем вы должны вручную удалить оставленную последовательность из столбца serial
. Запустите следующий запрос:
SELECT d.objid::regclass
FROM pg_depend AS d
JOIN pg_attribute AS a ON d.refobjid = a.attrelid AND
d.refobjsubid = a.attnum
WHERE d.classid = 'pg_class'::regclass
AND d.refclassid = 'pg_class'::regclass
AND d.deptype <> 'i'
AND a.attname = 'patientid'
AND d.refobjid = 'patient'::regclass;
Это должно дать вам имя последовательности, оставленной после столбца serial
. Отбросьте его, и столбец идентификаторов должен вести себя как нужно.
4
Laurenz Albe
5 Авг 2019 в 11:32
Это не ответ — извинения, но это позволяет мне наглядно показать сумасшедшее поведение, которое я (непреднамеренно) обнаружил сегодня утром …
Все, что мне нужно было сделать, это следующее:
alter TABLE db.generic_items alter column generic_item_id drop default;
alter TABLE db.generic_items alter column generic_item_id add generated by default as identity;
И теперь при написании сценария для таблицы SQL я получаю (сокращенно):
CREATE TABLE db.generic_items
(
generic_item_id integer NOT NULL GENERATED BY DEFAULT AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ),
generic_item_id integer NOT NULL GENERATED BY DEFAULT AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ),
generic_item_name character varying(50) COLLATE pg_catalog."default" NOT NULL,
CONSTRAINT pk_generic_items PRIMARY KEY (generic_item_id),
)
Я благодарен Лоренцу Альбе за опубликованный выше ответ ! Как он объясняет, просто удалите последовательность, которая использовалась для серийного значения по умолчанию, и это сумасшествие исчезнет, и таблица снова будет выглядеть нормально.
0
Wellspring
1 Окт 2019 в 14:40
Обновлять: Эта ошибка была исправлена в PostgreSQL v12 с фиксацией 19781729f78.
Остальная часть ответа актуальна для более старых версий.
Столбец serial имеет последовательность, которой владеет столбец, и значение DEFAULT, которое получает чистое значение последовательности.
Если вы попытаетесь изменить этот столбец на столбец идентификаторов, вы получите сообщение об ошибке, что для столбца уже есть значение по умолчанию.
Теперь вы, должно быть, отбросили значение по умолчанию, но не последовательность, принадлежащую столбцу serial. Затем, когда вы преобразовали столбец в столбец идентификаторов, была создана вторая последовательность, принадлежащая столбцу.
Теперь, когда вы пытаетесь вставить строку, PostgreSQL пытается найти и использовать последовательность в, принадлежащую столбцу, но их две, отсюда и сообщение об ошибке.
Я бы сказал, что это ошибка в PostgreSQL: на мой взгляд, он должен был либо переназначить существующую последовательность для столбца идентификаторов, либо дать вам ошибку, что уже существует последовательность, принадлежащая столбцу, и вы должны ее удалить. попробую исправить этот баг.
Между тем, вы должны вручную удалить последовательность, оставшуюся позади, из столбца serial.
Запустите следующий запрос:
SELECT d.objid::regclass
FROM pg_depend AS d
JOIN pg_attribute AS a ON d.refobjid = a.attrelid AND
d.refobjsubid = a.attnum
WHERE d.classid = 'pg_class'::regclass
AND d.refclassid = 'pg_class'::regclass
AND d.deptype <> 'i'
AND a.attname = 'patientid'
AND d.refobjid = 'patient'::regclass;
Это должно дать вам название последовательности, оставшейся после столбца serial. Отбросьте его, и столбец идентификаторов должен вести себя так, как хотелось бы.
do --check seq not in sync $$ declare _r record; _i bigint; _m bigint; begin for _r in ( Select DISTINCT(constraint_column_usage.table_name) as tablename, constraint_column_usage.column_name as idname, replace(replace(columns.column_default,'''::regclass)',''),'nextval(''','') as seqname, columns.table_schema as schamename from information_schema.constraint_column_usage, information_schema.columns where constraint_column_usage.table_schema ='public' AND columns.table_schema = 'public' AND columns.table_name=constraint_column_usage.table_name AND constraint_column_usage.column_name = columns.column_name AND columns.column_default is not null ) loop execute format('select last_value from %I.%s',_r.schamename,_r.seqname) into _i; execute format('select max(%I) from %I.%I',_r.idname,_r.schamename,_r.tablename) into _m; if coalesce(_m,0) > _i then raise info '%',concat('changed: ',_r.tablename||'_Id_seq',' from:',_i,' to:',_m+1); execute format('alter sequence %I.%s restart with %s',_r.schamename,_r.seqname,_m+1); end if; end loop; end; $$ ;
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
FlyWay + Spring Boot 2.x for vendor specific scripts error: found more than one migration with version 1.x
RichardK :
I’m trying to configure FlyWay to work with two vendors — one (H2) is for local environment, and another one (Mysql) is for ci.
Here’s my scripts patch:
My FlyWay bean configuration:
@Bean(initMethod = "migrate")
Flyway flyway() {
Flyway flyway = Flyway
.configure()
.dataSource(dataSource(dataSourceProperties()))
.locations("classpath:db/migration/MySQL", "classpath:db/migration/H2")
.load();
return flyway;
}
@Bean
@Primary
@ConfigurationProperties("spring.datasource")
public DataSourceProperties dataSourceProperties() {
return new DataSourceProperties();
}
@Bean
@ConfigurationProperties("spring.datasource")
public HikariDataSource dataSource(DataSourceProperties properties) {
return properties.initializeDataSourceBuilder().type(HikariDataSource.class)
.build();
}
And my application.yml configuration:
spring:
main:
allow-bean-definition-overriding: true
datasource:
driverClassName: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/messages
username: username
password: password
What I try to achieve is to make flyway run database vendor specific scripts, depending on which database is set in datasource. Here’s what I get:
Caused by: org.flywaydb.core.api.FlywayException: Found more than one migration with version 1.1
Offenders:
-> C:Projectsmy-projectoutproductionresourcesdbspecificMySQLV1_1__Create_table_message.sql (SQL)
-> C:Projectsmy-projectoutproductionresourcesdbspecificH2V1_1__Create_table_message.sql (SQL)
I’ve already tried to use lowercase vendor names (db/migration/mysql …) and use db/specific/ instead of db/migration. Nothing worked for me.
Mark Rotteveel :
The problem is your use of:
.locations("classpath:db/migration/MySQL", "classpath:db/migration/H2")
This will add both migrations to the runtime path. This is what causes the issue, because this configuration instructs flyway to always use the scripts from both locations, instead of only using the H2-scripts for H2 and the MySQL scripts for MySQL.
Instead, you should only add the specific path for the active driver on the path.
Something like
String driverVendor = ..; // something to decide h2 or mysql
Flyway flyway = Flyway
.configure()
.locations("classpath:db/migration/" + driverVendor)
You may need to lowercase the folder names, that is H2
to h2
and MySQL
to mysql
for this to work.
Alternatively, consider using Spring Boots Flyway auto-configuration instead of coding the Flyway configuration in code. This allows you to define the path in the application config as:
spring.flyway.locations=classpath:db/migration/{vendor}
Where {vendor}
will be automatically populated with the vendor name of the driver used to connect.
See also Execute Flyway Database Migrations on Startup
Collected from the Internet
Please contact [email protected] to delete if infringement.
edited at2020-03-10
Related
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
- Pick a username
- Email Address
- Password
By clicking “Sign up for GitHub”, you agree to our terms of service and
privacy statement. We’ll occasionally send you account related emails.
Already on GitHub?
Sign in
to your account
basis data / Problem Solved
24 Mar 2022 ahhandoyoLeave a comment
Identity columns don’t work if they own more than one sequence. you can remove more sequence.
You can remove by code:
ALTER SEQUENCE name_of_sequence OWNED BY NONE;
Leave a Reply
Enter your comment here…
Fill in your details below or click an icon to log in:
Email (required) (Address never made public)
Name (required)
Website
You are commenting using your WordPress.com account.
( Log Out /
Change )
You are commenting using your Facebook account.
( Log Out /
Change )
Cancel
Connecting to %s
Notify me of new comments via email.
Notify me of new posts via email.
This site uses Akismet to reduce spam. Learn how your comment data is processed.
do --check seq not in sync $$ declare _r record; _i bigint; _m bigint; begin for _r in ( Select DISTINCT(constraint_column_usage.table_name) as tablename, constraint_column_usage.column_name as idname, replace(replace(columns.column_default,'''::regclass)',''),'nextval(''','') as seqname, columns.table_schema as schamename from information_schema.constraint_column_usage, information_schema.columns where constraint_column_usage.table_schema ='public' AND columns.table_schema = 'public' AND columns.table_name=constraint_column_usage.table_name AND constraint_column_usage.column_name = columns.column_name AND columns.column_default is not null ) loop execute format('select last_value from %I.%s',_r.schamename,_r.seqname) into _i; execute format('select max(%I) from %I.%I',_r.idname,_r.schamename,_r.tablename) into _m; if coalesce(_m,0) > _i then raise info '%',concat('changed: ',_r.tablename||'_Id_seq',' from:',_i,' to:',_m+1); execute format('alter sequence %I.%s restart with %s',_r.schamename,_r.seqname,_m+1); end if; end loop; end; $$ ;