2013-11-19 2 views
0

Установите кредитный лимит на всех клиентов до 0, когда клиенты Когда они получили напоминание в 2008 и 2009Возможно ли, что этот запрос возможен без подзапроса?

Упрощенные столы

Create table customer (id int, credit_limit int); 
Create table Bill (id int, customer_id int, date datetime); 

Мой подход:

Update customer 
    set credit_limit = 0 
where (select customer_id 
     from bills 
     where year(reminder) = 2008) 
    and (select customer_id 
     from bills 
     where year(reminder) = 2009) 
+0

Что СУБД вы используете? –

+0

Oracle 11g express –

+0

Операторы 'create table' не соответствуют вашему запросу на обновление (' bills' против 'bill',' date' и 'reminder'). В Oracle также нет типа данных 'datetime'. –

ответ

2

Возможно, что-то вроде этого:

UPDATE customer set credit_limit = 0 
WHERE EXISTS 
    (
     SELECT 
      NULL 
     FROM 
      bills 
     WHERE 
      bills.customer_id=customer.customer_id 
      AND year(bills.reminder) IN (2008,2009) 
    ) 

Или если вы хотите проверить, что существуют как 2008, так и 2009 год. Затем вы можете сделать

UPDATE customer set credit_limit = 0 
WHERE EXISTS 
    (
     SELECT 
      NULL 
     FROM 
      bills 
     WHERE 
      bills.customer_id=customer.customer_id 
      AND year(reminder) = 2008 
    ) 
    AND EXISTS 
    (
     SELECT 
      NULL 
     FROM 
      bills 
     WHERE 
      bills.customer_id=customer.customer_id 
      AND year(reminder) = 2009 
    ) 
+1

Как это не подзапрос? Оракул как-то оптимизирует выбор? – Tobberoth

+2

Да, это подзапрос. Но при соединении вам нужно отсканировать все значения. При существовании он будет останавливаться, когда он будет соответствовать. Я просто думаю, что нет необходимости присоединяться, когда он не использует значения в инструкции обновления. А также с риском иметь отношение «один к большому» между клиентом и векселем. Он будет обновлять больше значений, необходимых для соединения, а затем существует. Поэтому он заставил меня поверить, что существует быстро, а затем присоединяется – Arion

+0

+1: EXISTS - это «semijoin» и будет либо быстрее (или, по крайней мере, не медленнее, чем соединение), как вы говорите. –

0

Это должно сделать трюк в Oracle:

update 
    (
    select 
     c.id, 
     c.credit_limit, 
    from customer c 
     inner join Bill b1 on 
      c.id = b1.customer_id and year(b1.date) = 2008 
     inner join Bill b2 on 
      c.id = b2.customer_id and year(b2.date) = 2009 

    ) up 
set up.credit_limit = 0 
+1

Вам нужно будет выбрать столбцы первичного ключа из таблицы 'customer' (во внутреннем выборе), иначе это не сработает –

+0

@a_horse_with_no_name спасибо, отредактирован. – Alex

-1
Update customer set credit_limit = 0 
Inner join Bill b1 on customer.id = b1.customer_id 
join Bill b2 on b1.customer_id = b2.customer_id and year(b1.reminder) = 2009 and year(b2.reminder) = 2008 
+0

Это неверно для Oracle –

0

Я не думаю, что это возможно без подзапроса (сокр использования MERGE - но это будет все равно будет чем-то вроде подзапроса).

Вы можете упростить подзапрос, чтобы сделать его более эффективным (и правильно)

update customer 
    set credit_limit = 0 
where id in (select customer_id 
      from bills 
      where extract(year from reminder) in (2008, 2009) 
      group by customer_id 
      having count(distinct extract(year from reminder)) = 2) 
Смежные вопросы