Клонировать строку с первичным ключом в SQL? - PullRequest
2 голосов
/ 05 января 2010

Я пытаюсь создать кросс-DB (SQL Server и PostgreSQL) совместимый SQL. Что мне нужно сделать, это клонировать строку. Желательно делать это локально на сервере SQL без необходимости извлекать всю строку до нашего клиента и повторно вставлять ее. Кроме того, мы предпочитаем не создавать новый запрос SQL с нуля, динамически вставляя имена столбцов, но я полагаю, что это вариант.

Например: У нас есть адресная таблица в этой таблице, например: address_rid: целое число, первичный ключ, автоинкремент, не нуль адрес1: варчар (100) адрес2: varchar (100)

Итак, наша цель - просто клонировать одну из этих строк так, чтобы address1 и address2 были одинаковыми, но для address_rid будет установлено следующее значение, как обычно.

Как бы вы поступили так?

Кроме того, я видел Самый быстрый способ клонировать строки в SQL

который имеет

<code>
INSERT INTO PrimKeys 
SELECT 'PrimKey2' AS PrimKey,* 
  FROM PrimKeys 
 WHERE PrimKey='PrimKey1'

У меня проблемы с тем, чтобы что-то подобное работало на postgres, а также использовало что-то вроде default для вставляемого первичного ключа.

редактирование: Кроме того, я бы также взял 2 отдельных запроса, которые будут делать это на SQL Server и Postgres, хотя я предпочел бы просто поддерживать 1 запрос.

и я использую C # ado.net в качестве моего клиента.

Ответы [ 3 ]

3 голосов
/ 05 января 2010

Я не уверен насчет PostgreSQL, но если он поддерживает автоинкремент, как это делают большинство систем, тогда просто оставьте поле первичного ключа пустым. Однако это означает, что вам нужно указать имена столбцов.

Кроме того, когда вы говорите клон, это звучит так, как будто вы хотите получить копию своей записи, но в вашем описании столбцы address1 и address2 находятся в одной строке данных.

Если вы хотите скопировать свой адрес1 в столбец адреса2, вы можете использовать простое заявление об обновлении.

Если вы пытаетесь клонировать всю строку, чтобы получить две одинаковые записи, вы можете использовать что-то подобное, и это должно работать в обеих средах.

INSERT INTO Addresses
( address1, address2 )
SELECT address1, address2
  FROM Addresses
 WHERE addressId = ID

Теперь следующий вопрос: клонируете ли вы из одного типа БД в другой? Если это так, то вам все равно нужно будет вставить его в ваше приложение. Если да, то почему бы вам не использовать что-то вроде nHibernate, чтобы абстрагировать слой db от вас.

Если цель состоит в том, чтобы просто сделать копию, то вы можете сделать это прямо в БД с помощью sql выше.

Хотя этот sql, вероятно, самый простой (и вы можете отразить его в БД, если это необходимо, используя системные / основные таблицы), вам все равно нужно будет указать имена столбцов. Основная причина заключается в том, что, как только вы добавите подстановочный знак *, он все равно попытается включить ваш исходный столбец первичного ключа в список выбора, который будет иметь еще 1 дополнительный столбец к тому, что у вас есть.

Другая проблема, о которой следует помнить при использовании подстановочных знаков в операторах вставки, заключается в том, что ваш столбец упорядочивает ДОЛЖЕН СОВПАДАТЬ в противном случае вы получите очень неожиданные результаты.

2 голосов
/ 05 января 2010

Postgres, как и Oracle, использует последовательности для генерации последовательных числовых значений для искусственных / суррогатных ключей. Чтобы получить следующее значение, вам нужно использовать:

NEXTVAL(your_sequence_name) 

... в вашем операторе INSERT, чтобы установить значение для первичного ключа. Вы не сможете опустить его в своем выражении INSERT, если только по какой-то странной причине столбец не обнуляется. Так что на Postgres вам нужно использовать:

INSERT INTO PrimKeys 
SELECT NEXTVAL(your_sequence_name),
       [rest of columns, because you can't include the pk col/value]
  FROM PrimKeys 
 WHERE PrimKey='PrimKey1'

Эквивалентная функциональность SQL Server

SQL Server (и MySQL) позволяют либо не указывать столбец, либо указывать NULL в качестве заполнителя для столбца первичного ключа, и предоставит значение для вас. Это так близко, как вы получите.

Справка:

0 голосов
/ 25 мая 2012

Немного опоздал на вечеринку, но эта функция может помочь людям.

Создать агрегатную функцию для разделения текстовых значений в результате, запятую будет использовать для получения списка столбцов.

CREATE OR REPLACE FUNCTION concat_delimited( TEXT, TEXT, TEXT ) RETURNS TEXT AS $$
  SELECT $1 || (CASE WHEN $1 = '' THEN '' ELSE $3 END) || $2;
$$
LANGUAGE SQL STRICT IMMUTABLE;

CREATE AGGREGATE delimited_list_of ( TEXT, TEXT ) (
  SFUNC = concat_delimited,
  STYPE = TEXT,
  INITCOND = ''
);

Создать функцию для дублирования записей

 CREATE OR REPLACE FUNCTION  duplicate(_schema text,_tbl text, _id integer)
 RETURNS integer AS 
 $BODY$
 DECLARE cols text;
   sql  text;
   result integer;
 BEGIN
   SELECT into  cols  delimited_list_of(column_name, ',') 
   FROM   information_schema.columns 
   WHERE  table_schema =  _schema  AND table_name = _tbl  AND  column_name != 'id';

   raise notice 'Cols: %', cols;
   sql := 'insert into ' || quote_ident(_schema) || '.' || quote_ident(_tbl) || '('  
       || cols ||  ') SELECT ' || cols || ' FROM ' || quote_ident(_schema) || '.' 
       || quote_ident(_tbl) || ' WHERE id = ' || _id || ' RETURNING id' ;

    raise notice 'Query: %', sql;
    EXECUTE sql  into result;
    RETURN result;
 END;
 $BODY$
   LANGUAGE  plpgsql VOLATILE  COST 100;

Оттуда просто передайте имя схемы, имя таблицы и идентификатор записи, подлежащей дублированию, и она вернет идентификатор созданной записи. * 1009 например *

select  duplicate('_schema','test_tbl',500001);

вам нужно будет изменить идентификатор имени поля на то, какое у вас первичное / уникальное имя поля.

...