2012-04-26 3 views
1

у меня есть этот запросInsert просит

INSERT INTO SERVICEPAYANT_CLIENT (RE_ID, TYPE_DONNEES) 
SELECT CLIENT_ID, 160 AS TYPE_DONNEES 
FROM REFERENTIEL r, CLIENT_APPLICATIF ca 
WHERE r.ID = ca.ID_REFERENTIEL 
AND r.TYPE=1 
GROUP BY CLIENT_ID 
HAVING COUNT(*)>0; 

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

+0

http://stackoverflow.com/q/108403/284240 –

ответ

2

Вы можете сделать:

INSERT INTO SERVICEPAYANT_CLIENT (RE_ID, TYPE_DONNEES) 
SELECT CLIENT_ID, 160 AS TYPE_DONNEES 
FROM REFERENTIEL r, CLIENT_APPLICATIF ca 
WHERE r.ID = ca.ID_REFERENTIEL 
AND r.TYPE=1 
AND NOT EXISTS (
    SELECT * FROM SERVICEPAYANT_CLIENT sp 
    WHERE sp.RE_ID = CLIENT_ID AND TYPE_DONNEES = 160) 
GROUP BY CLIENT_ID 
HAVING COUNT(*)>0; 

«И НЕ СУЩЕСТВУЕТ ...» это то, что ограничивает его возвращения строки, которые уже не в целевой таблице.

1

Типичным решением было бы обеспечить его применение в базе данных с уникальным ограничением, состоящим из полей, которые определяют запись. Ваш код Java затем получит ошибку из базы данных, сообщив вам, что она уже существует.

+1

+1. Я собирался предложить добавить предложение «if exists» перед запуском этого сценария SQL, но он будет подвержен синтаксическим ошибкам в зависимости от базы данных и, что более важно, он не должен быть вставлен несколько раз в любом случае, и это база данных работу, чтобы обеспечить это, а не программиста. – Neil

+0

Это действительно зависит от вашего приложения. Если у вас есть контроль над базой данных, то добавление ограничения - это хорошая инкапсуляция ваших правил. Но если объем транзакций является массовым, и вы ожидаете, что большинство ваших записей уже существует, тогда будет гораздо эффективнее обрабатывать его в SQL. – Greg

+1

Правда, но дело в том, что это не должно произойти и должно рассматриваться как исключение, а не правило. Поэтому либо программист ловит исключения ограничений, либо еще лучше, он избегает нескольких вызовов сам, и вы получаете как эффективность, так и правильность. – Neil

1

Вы можете сделать это:

INSERT INTO SERVICEPAYANT_CLIENT (RE_ID, TYPE_DONNEES) 
SELECT CLIENT_ID, 160 AS TYPE_DONNEES 
REFERENTIEL r 
JOIN CLIENT_APPLICATIF ca 
    ON r.ID = ca.ID_REFERENTIEL 
WHERE 
    r.TYPE=1 
    AND NOT EXISTS 
     (
      SELECT 
       NULL 
      FROM 
       SERVICEPAYANT_CLIENT 
      WHERE 
       REFERENTIEL.CLIENT_ID=SERVICEPAYANT_CLIENT.RE_ID 
     ) 
GROUP BY CLIENT_ID 
HAVING COUNT(*)>0; 
1

Существует предложение MERGE в нескольких зрелой СУБД для этих случаев. MERGE - INSERT и UPDATE в то же время.

Общий синтаксис Пример:

 MERGE INTO TABLE_NAME USING table_reference ON (condition) 
     WHEN MATCHED THEN 
     UPDATE SET column1 = value1 [, column2 = value2 ...] 
     WHEN NOT MATCHED THEN 
     INSERT (column1 [, column2 ...]) VALUES (value1 [, value2 ... 

Некоторые СУБД, такие как MySQL имеет свой собственный синтаксис с той же идеей. См. Больше в Wikipedia.

Если ваша СУБД не соппует, тогда вы можете написать хранимую процедуру с той же логикой.

Но хранимая процедура или любая другая проверка вашего кода перед вставкой сделают «задержку», и операция станет «неатомной». Это означает, что возможно, что сразу после проверки и перед вставками другая транзакция может сделать дублируемую запись, и вы получите неожиданные дубликаты или экскременты. Чтобы этого избежать, вам нужно заблокировать таблицу перед этой операцией, чтобы получить эксклюзивный доступ к таблице, что может привести к штрафу за порфиману из-за сериализации доступа.

Или вы можете использовать INSERT с SELECT, как это:

INSERT (field1, ...) INTO table1 
    SELECT value1, ... 
    FROM DUAL -- put a name of analogue of Oracle's DUAL here 
    WHERE NOT EXISTS (
     SELECT 1 
     FROM table1 
     WHERE key = :new_key 
    ) 

Но, как вы понимаете, это не будет ничего обновлять.