Как заменить подзапрос в предложении where? - PullRequest
1 голос
/ 26 сентября 2019

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

<cfquery name="findStores" datasource="test">
    SELECT store_id, year_id, start_dt, end_dt 
    FROM stores 
    WHERE store_id= #storeID# 
        AND year_id = #yearID# 
        AND store_type_id IN (5,6,7,8,9,10)
</cfquery>

<cfloop query="findSubAgencies">    
    <cfscript>
        storeID= store_id;
        yearID = year_id;
        startDt = start_dt;
        endDt = end_dt;
    </cfscript>
    <cfquery name="updateStatus" datasource="test">
        UPDATE store_status
        SET start_date = '#start_dt#',
            end_date = '#end_dt#',
            last_update_date = getDate()
        WHERE status_id = (
             SELECT status_id 
             FROM store_status 
             WHERE store_id = #storeID# 
                AND year_id = #yearID#
        )
    </cfquery>

    <cfquery name="updateStoreDoc" datasource="test">
        UPDATE store_doc
        SET approve_start_date = '#start_dt#',
            approve_end_date = '#end_dt#',
            status_id = (SELECT max(status_id) FROM store_status WHERE store_id = #storeID# AND year_id = #yearID#)
        WHERE store_id = #storeID# 
            AND year_id = #yearID#
    </cfquery>
</cfloop>

Код выше перебирает запрос findStores и обновляет две разные таблицы.Мне было интересно, если это все можно сделать в Sybase SQL?Вместо того, чтобы зацикливаться на запросе и иметь два дополнительных внутренних запроса, можем ли мы просто использовать временную таблицу или WHERE IN () для достижения того же результата?Если у кого-то есть предложения, пожалуйста, дайте мне знать.

Ответы [ 3 ]

1 голос
/ 26 сентября 2019

Я давно не видел ColdFusion ... этот тег CFQUERY возвращает хорошие воспоминания :)

Если вы выполняете тот же запрос UPDATE для нескольких записей, выдолжен выполнить один пакетный запрос (как вы предложили).Чтобы сделать это для всех магазинов, вы можете использовать вариант вашего запроса findStores в качестве источника для ваших UPDATE s, что-то вроде этого:

<!--- Update status --->
<cfquery name="updateStatus" datasource="test">
  UPDATE store_status tgt
  FROM (
    -- findStores query
    SELECT store_id, year_id, start_dt, end_dt 
    FROM stores 
    WHERE store_type_id IN (5,6,7,8,9,10)
  ) src
  SET start_date = src.start_dt,
    end_date = src.end_dt,
    last_update_date = getDate()
  WHERE status_id = (
    SELECT status_id 
    FROM store_status 
    WHERE store_id = src.store_id 
    AND year_id = src.year_id
  )
</cfquery>

<!--- Update store info --->
<cfquery name="updateStoreDoc" datasource="test">
  UPDATE store_doc tgt
  FROM (
    -- findStores query with MAX(status) calculation
    SELECT 
      st.store_id, st.year_id, st.start_dt, st.end_dt, 
      MAX(stt.status_id) AS status_id_max
    FROM stores st
    LEFT JOIN store_status stt ON st.store_id = stt.store_id -- Get status info
      AND st.year_id = stt.year_id
    WHERE st.store_type_id IN (5,6,7,8,9,10)
    GROUP BY 1,2,3,4
  ) src
  SET approve_start_date = src.start_dt,
    approve_end_date = src.end_dt,
    status_id = src.status_id_max
  WHERE store_id = src.store_id
  AND year_id = src.year_id
</cfquery>

Я не уверен, что ваша базовая СУБДподдерживает этот синтаксис и то, как Cold Fusion будет его обрабатывать, поэтому может потребоваться некоторая обработка, чтобы заставить его работать.

Кроме того, что именно вы пытаетесь сделать в запросе updateStatus?Вы ссылаетесь на status_id в своем предложении WHERE, но не на store_id и year_id.Напротив, запрос updateStoreDoc ссылается на оба этих поля в предложении WHERE.Я не уверен, что приведенный выше запрос будет работать правильно для updateStatus в этой форме без ссылки на PK таблицы.

И последнее, что нужно учитывать, это то, что таблица store_status обновляется в первомпакетный запрос, а затем ссылка во втором пакетном запросе.Возможно, вам придется изменить порядок этих запросов в зависимости от ожидаемого конечного результата.

1 голос
/ 26 сентября 2019

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

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

<cfquery datasource="test">
    update store_status
    set start_date = stores.start_date
        , end_date = stores.end_date
        , last_update_date = getDate()
    from store_status
        inner join stores on store_status.store_id = stores.store_id
            and store_status.year_id = stores.year_id
    WHERE stores.store_id = <cfqueryparam value="#storeID#" />
        and stores.year_id = <cfqueryparam value="#yearID#" />
        and stores.store_type_id IN (5,6,7,8,9,10);

    update store_doc
    set approve_start_date = stores.start_date
        , approve_end_date = stores.end_date
        , status_id = (SELECT max(status_id) FROM store_doc WHERE store_id = stores.store_id AND year_id = stores.year_id)
    from store_doc
        inner join stores on store_doc.store_id = stores.store_id
            and store_doc.year_id = stores.year_id
    WHERE stores.store_id = <cfqueryparam value="#storeID#" />
        and stores.year_id = <cfqueryparam value="#yearID#" />
        and stores.store_type_id IN (5,6,7,8,9,10)
</cfquery>
1 голос
/ 26 сентября 2019

Вот общая идея (для явных идентификаторов):

declare 
  @storeID int, @yearID int
begin
  set @storeID = 1
  set @yearID = 2019

        UPDATE store_status dest
        SET start_date = src.start_dt,
            end_date = src.end_dt,
            last_update_date = getDate()
        FROM stores src
        WHERE dest.store_id = src.store_id 
                AND dest.year_id = src.year_id
                AND src.store_id=@storeID
                AND src.year_id=@yearID

end
go

Цикл по магазинам:

        UPDATE store_status dest
        SET start_date = src.start_dt,
            end_date = src.end_dt,
            last_update_date = getDate()
        FROM stores src
        WHERE dest.store_id = src.store_id 
                AND dest.year_id = src.year_id
               AND store_type_id IN (5,6,7,8,9,10)
go

UPDATE store_doc dest
SET approve_start_date = src.start_dt,
    approve_end_date = src.end_dt,
    status_id = max_status_id
FROM (SELECT max(status_id) max_status_id, max(start_date) start_dt,
         max(end_date) end_dt, store_id, year_id FROM store_status 
      GROUP BY store_id, year_id) src
WHERE dest.store_id = src.store_id 
    AND dest.year_id = src.year_id

go
...