2011-07-28 4 views
21

먼저, 여기에 문제의 간결한 요약이다 :MySQL은 INSERT IF (if 문 정의)

이 가능 조건부 INSERT 문을 실행하는가? 이 가깝다 뭔가 :

IF(expression) INSERT... 

지금, 내가 저장 프로 시저와 함께이 작업을 수행 할 수 있습니다 알고 있습니다. 내 질문에 : 내 쿼리에서이 작업을 수행 할 수 있습니까?


지금 내가 왜 그렇게하고 싶습니까?

의 우리는 다음과 같은 두 테이블이 있다고 가정하자.의 20 개 부두 인형 (제품 ID 2)에 대한 주문이 들어오는 말을하자, 이제

products: id, qty_on_hand 
orders: id, product_id, qty 

을 충분한 수량이 손에있을 경우
우리는 먼저 확인 : 이 true로 평가되면

SELECT IF(
    (SELECT SUM(qty) FROM orders WHERE product_id = 2 ) + 20 
    <= 
    (SELECT qty_on_hand FROM products WHERE id = 2) 
, 'true', 'false'); 

그런 다음, 우리는 INSERT 쿼리를 실행합니다.
지금까지 너무 좋아.


그러나 동시성에는 문제가 있습니다.
정확히 같은 시간에 2 주문이 들어 오면, 주문 중 하나가 주문에 들어가기 전에 양 수량을 모두 읽을 수도 있습니다. 둘 다 주문을하게되며 따라서 qty_on_hand을 초과합니다. 그래서 다시 질문의 루트에


:
우리가 하나에 이러한 쿼리를 모두 결합 할 수 있도록 조건부 INSERT 문을 실행할 수 있습니까?

내가 많이 찾을 수있는 조건문 INSERT의 진술은 ON DUPLICATE KEY이며 여기서는 분명히 적용되지 않습니다.

답변

38
INSERT INTO TABLE 
SELECT value_for_column1, value_for_column2, ... 
FROM wherever 
WHERE your_special_condition 

특수 조건이 false이기 때문에 select에서 행이 반환되지 않으면 삽입이 발생하지 않습니다.

질문에서 스키마를 사용합니다 (id 열이 auto_increment입니다 가정) : 손에 충분한 재고가 아니라면

insert into orders (product_id, qty) 
select 2, 20 
where (SELECT qty_on_hand FROM products WHERE id = 2) > 20; 

이 더 행을 삽입하지 않습니다, 그렇지 않으면 주문 행을 생성합니다.

멋진 아이디어 btw!

+0

@ 보헤미안 : 두 개의 SELECT 문 필요 없음. 하나는 충분할 것입니다. 내 대답 좀 봐. :) – Shef

+0

사실,하지만 내 * 일반 * 패턴과 일치 시키려고했습니다. 나는 당신의 대답을 좋아합니다 ... +1 – Bohemian

+0

@Joseph Silber : 무엇을 할 ??? 거기에서 뺄셈은 어디에 있습니까? 뺄셈은 정규화와 어떤 관련이 있습니까? : D 위의 쿼리가 내 것과 비교되는 두 개의 SELECT 문으로 구성된다는 것을 알고 계십니까? (당신의 대답이나 당신, 보헤미안에 대한 어떤 것도). – Shef

2

아마 문제를 잘못 풀 수 있습니다.

두 개의 읽기 작업이 동시에 발생하므로 하나가 부실 데이터로 작동 할 경우 잠금 또는 트랜잭션을 사용하는 것이 해결책입니다.

조회가 이렇게 유무 :

  • 잠금 테이블을 읽기
  • 읽기 테이블
  • 업데이트 테이블
  • 동시성에 대한 분리 잠금이
+0

잠금이 가장 좋은 솔루션인지 잘 모르겠습니다. 심각한 성능 문제가 발생할 수 있습니다. –

2

확실하지, 당신은해야합니다 mysql에서 잠금을 읽을 수 있지만, 20 개 항목을 사용할 수있는 경우에만 20 개 항목 만 가져갈 수 있습니다.

update products 
set qty_on_hand = qty_on_hand - 20 
where qty_on_hand >= 20 
and id=2 

영향을받은 행 수를 확인할 수 있습니다. 아무 것도 영향을받지 않으면 주식이 충분하지 않은 것입니다. 1 행이 영향을 받으면 유효하게 주식을 소비했습니다.

16

보십시오

2 동일 id 가진 제품이 존재하고 qty_on_hand이 제품 20보다 크거나 같은
INSERT INTO orders(product_id, qty) 
SELECT 2, 20 FROM products WHERE id = 2 AND qty_on_hand >= 20 

경우, 삽입이 값 product_id = 2qty = 20 발생할 것이다. 그렇지 않으면 삽입이 발생하지 않습니다.

: 제품 ID는 서로 참고하는 경우, 당신은 SELECT 문장의 끝에 LIMIT 절을 추가 할 수 있습니다.

+0

당신은 어떻게 이것을 부정합니까? – user2340939

+0

한 가지 방법은 끝에 다음을 추가하는 것입니다. HAVING COUNT (*) = 0. – user2340939