SQL Серверная база данных запрашивается python программными ошибками с тем же кодом SQL, который отлично работает непосредственно на SQL Сервере - PullRequest
0 голосов
/ 07 марта 2020

У меня есть доступ только для чтения к SQL базе данных сервера. Я хочу использовать мою Python программу, расположенную на том же компьютере, что и серверная база данных SQL, чтобы запросить ее с помощью SELECT. Попытка хранимой процедуры ниже также является оператором SELECT. Я использую модуль pyodb c в Python.

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

При первой попытке я создал оператор SQL, который имел общее выражение таблицы, и четыре оператора SELECT с несколькими INNER JOIN и LEFT OUTER JOIN, к которым присоединяются UNION ALL операторы. Запрос возвращает правильный результат в текстовом редакторе запросов к серверу SQL, но не из моей программы Python. В программе Python она пропускает часть запроса, полученную из части Common Table Expression. При запуске из текстового редактора запросов SQL Server он возвращает результаты с общей частью табличного выражения. Однако Python и pyodb c работают без ошибок, хотя он не возвращает ничего из части Common Table Expression, когда запрос выполняется из программы Python. После попытки 1 я решил использовать альтернативу выражениям Common Table и не пытался сделать это при попытке 2 и 3.

Моя вторая попытка - создать представление на сервере SQL непосредственно на SQL База данных сервера и это представление возвращают ту же самую информацию, которую ранее делало общее выражение таблицы (теперь я могу подставить представление в свой запрос вместо общего выражения таблицы). Когда я запускаю эту попытку, я получаю сообщение об ошибке:

pyodb c .ProgrammingError: ('42S02', ”[42S02] [Microsoft] [ODB C Драйвер 17 для SQL Сервер] [SQL Сервер] Неверное имя объекта 'dbo.VW_VIEW_NAME'. (208) (SQLExecDirectW) ").

Когда я пытаюсь запустить этот dbo.VW_VIEW_NAME на SQL Сервере база данных, использующая New Query, возвращает искомый набор результатов, но не при попытке с Python и pyodb c. На SQL сервере я могу просматривать вид с помощью обозревателя объектов и искать в папке видов. Я могу щелкнуть правой кнопкой мыши на представлении, создать оператор выбора и выполнить его с результатами. У меня есть только одна учетная запись для доступа к базе данных, и она имеет только разрешение на чтение. Код SQL, вызывающий представление в окне запроса в SQL Сервер работает нормально. Все они используют те же SQL учетные данные для входа на сервер, что и программа python.

Поэтому SQL Сервер, по-видимому, не позволяет программе Python и модулю pyodb c получить доступ к SQL Объекты базы данных сервера.

Моя третья попытка - переместить весь запрос SQL из программы Python в SQL серверную хранимую процедуру и просто выполнить хранимую процедуру из моего * Код 1088 * (Таким образом, код SQL все выполняется в базе данных без возможности возникновения проблем из-за пределов базы данных.) Администратор базы данных предоставил мне разрешение EXECUTE для моих хранимых процедур. Я снова получаю сообщение об ошибке, аналогичное ошибке с представлением:

pyodb c .ProgrammingError: ('42000', '[42000] [Microsoft] [ODB C Драйвер 17 для SQL Сервер] [SQL Сервер] Не удалось найти хранимую процедуру 'dbo.USP_MY_STORED_PROCEDURE'. (2812) (SQLExecDirectW) ").

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

То есть, входит ли pyodb c на сервер SQL и получает доступ к представлению или на SQL сервер и обращаясь к хранимой процедуре, результат тот же: он не говорит, что знает что-либо об этих объектах.

Похоже, SQL Сервер может блокировать доступ pyodb c и Python к просмотреть в одной попытке запроса, а хранимую процедуру в другой попытке запроса. Есть ли что-то, что мне нужно исправить на SQL Сервере, чтобы позволить представлению и хранимой процедуре быть доступными для внешних программ?

При попытке решить эту проблему на отдельных шагах по устранению неполадок я сделал следующее : обновленная версия python до последней обновленной версии Wing IDE до последней обновленной версии pyodb c до последней версии прочитана полностью python DB 2.0 API прочитана вся документация pyodb c прочитано много ссылок в поисковых системах

Ни одна из этих попыток не дала мне ответа.

Является ли проблема вопросом SQL Сервер блокирует доступ для просмотра объектов и объектов хранимых процедур извне? Есть ли в SQL Сервере параметр, позволяющий проходить через эти вещи, которые необходимо соответствующим образом настроить?

Вот код python, ведущий к cursor1.execute ("...") оператор

        conn1 = pyodbc.connect('DRIVER={ODBC Driver 17 for SQL Server}'
                                       +';SERVER='+server1+'; UID='+username1+'; PWD='+password1+';DATABASE='+database1)
        cursor1 = conn1.cursor()
        print('Before cursor 1 execute sql code ' + str(datetime.datetime.now()))
        cursor1.execute(r"""

Моя python версия, использующая 3.8.2

pyodb c версия использующая: 4.0.30

SQL Версия сервера SQL Server 2017

Операционная система Windows Server 2012

Спасибо за помощь в решении этой проблемы.

1 Ответ

0 голосов
/ 08 марта 2020

Для AlwaysLearning, этот ответ посвящен попытке базы данных, которая передает код SQL в базу данных и пытается использовать представление.

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

ошибка, полученная в строке cursor1.execute (r "" "

pyodb c .ProgrammingError: ('42S02'," [42S02] [Microsoft] [ODB C Драйвер 17 для SQL Сервер] [SQL Сервер] Неверное имя объекта 'dbo.VW_TB_TERM_SALE_ENTRIES'. (208) (SQLExecDirectW) ")

Теперь для программы python до точка возникновения ошибки:

import LOG_INTO_HOTMAIL_SEND_ATTACH2
import datetime

import LOG_INTO_HOTMAIL_EMAIL_MESSAGE

import time

import CALCULATE_TERM_SALE_DISCOUNTED_PRICE

import pyodbc

# import pymssql

def ACCESS_DATABASE_WEBSTORE_QOH_DATA_4th_Attempt():

    UPC_CODE_QOH_Dictionary = {}
    UPC_CODE_QOH_Dictionary.clear()

    UPC_CODE_Cost_Dictionary = {}
    UPC_CODE_Cost_Dictionary.clear()

    UPC_CODE_Retail_Dictionary = {}
    UPC_CODE_Retail_Dictionary.clear()

    UPC_CODE_Compare_at_Price_Dictionary = {}
    UPC_CODE_Compare_at_Price_Dictionary.clear()

    # List_UPC_CODE_Add_Cost_and_Retail_At_End = []

    bln_Success = False

    while bln_Success is not (True):

        # ENCAPSULATE THE REST OF THE WHILE LOOP IN A TRY-EXCEPT BLOCK. SET bln_Success to True when 
        # the whole of the try block is successfully traversed.

        strErrorString = ''
        # server1 = "DESKTOP-24681012\\SQLEXPRESS_LWD"
        server1 = '123.456.78.90'
        database1 = 'db_name'
        # username1 = "DESKTOP-24681012\\lwdur"
        username1 = 'USERNAME_READ_ACCESS'
        password1 = 'Ab335**1'

        #try:

        conn1 = pyodbc.connect('DRIVER={ODBC Driver 17 for SQL Server}'
                                       +';SERVER='+server1+'; UID='+username1+'; PWD='+password1+';DATABASE='+database1)
        cursor1 = conn1.cursor()

        print('Before cursor 1 execute sql code ' + str(datetime.datetime.now()))

    -- THE BELOW cursor1 LINE IS WHERE THE ERROR IS GENERATED.
        cursor1.execute(r"""

                -- BELOW COMMENTS ARE THE 1ST ATTEMPT USING COMMON TABLE EXPRESSION.
                -- DATA TO BE RETRIEVED USING THE CTE WAS NOT RETRIEVED USING THIS
                -- PYTHON PROGRAM, THEREFORE I COMMENTED IT OUT AND ADDED THIS TO
                -- THE VIEW.

                                -- USE Celerant;
                                -- GO
                                -- WITH Term_Sale_Entries_CTE (STYLE_ID, ATTR1_ENTRY_ID, ATTR2_ENTRY_ID
                                -- , AMOUNT, ROUNDING, TYP, STORE_ID)
                                -- AS
                                -- (
                                -- SELECT STYLE_ID, ATTR1_ENTRY_ID, ATTR2_ENTRY_ID
                                -- , AMOUNT, ROUNDING, TYP, STORE_ID
                                -- FROM dbo.TB_TERM_SALE_ENTRIES
                                -- WHERE
                                -- GETDATE() BETWEEN [START_DATE]
                                -- AND END_DATE
                                -- AND (STORE_ID = 1
                                -- OR
                                -- STORE_ID = 99)
                                --ORDER BY STYLE_ID ASC
                                -- )
                                -- END OF COMMON TABLE EXPRESSION

-- BEGIN OF PORTION 1 OF UNION ALL SEGMENT
                                SELECT dbo.TB_STYLES.BRAND, dbo.TB_STYLES.STYLE ,
                                dbo.TB_STYLES.[DESCRIPTION], dbo.TB_STYLES.WEB_PRODUCT,
                                dbo.TB_SKU_BUCKETS.QOH, dbo.TB_SKU_BUCKETS.PRICE,
                                dbo.TB_SKU_LOOKUPS.[LOOKUP] AS UPC_CODE, TB_SKU_BUCKETS.AVG_COST,
                                dbo.VW_TB_TERM_SALE_ENTRIES.AMOUNT AS TERM_SALE_ENTRIES_AMOUNT,
                                dbo.VW_TB_TERM_SALE_ENTRIES.ROUNDING AS TERM_SALE_ENTRIES_ROUNDING,
                                dbo.VW_TB_TERM_SALE_ENTRIES.TYP AS TERM_SALE_ENTRIES_TYP,
                                dbo.VW_TB_TERM_SALE_ENTRIES.STYLE_ID
                                -- DELETE THIS ENTRY NEXT TO REVERT BACK TO ORIGINAL:
                                --INTO #TEMP_CURSOR_1_RESULTS
                                --,
                                -- dbo.TB_SKUS.SKU_OF3
                                FROM dbo.TB_STYLES
                                INNER JOIN dbo.TB_SKUS
                                ON dbo.TB_STYLES.STYLE_ID = dbo.TB_SKUS.STYLE_ID
                                INNER JOIN dbo.TB_SKU_BUCKETS
                                ON dbo.TB_SKUS.SKU_ID = dbo.TB_SKU_BUCKETS.SKU_ID
                                INNER JOIN dbo.TB_SKU_LOOKUPS
                                ON (
                                dbo.TB_SKUS.SKU_ID = dbo.TB_SKU_LOOKUPS.SKU_ID 
                                -- TB_SKU_LOOKUPS.SKU_ID CAN BE NULL BUT THIS IS OF NO CONSEQUENCE.
                                -- isnull(dbo.TB_SKUS.SKU_ID, -999)
                                -- =
                                -- isnull(dbo.TB_SKU_LOOKUPS.SKU_ID, -999)
                                )
                                LEFT OUTER JOIN dbo.TB_ATTR1_ENTRIES
                                ON  (dbo.TB_SKUS.ATTR1_ENTRY_ID = dbo.TB_ATTR1_ENTRIES.ATTR1_ENTRY_ID) 
                                -- TB_ATTR1_ENTRIES.ATTR1_ENTRY_ID IS "NOT NULL". THEREFORE NO NEED TO CHECK FOR NULLS.
                                LEFT OUTER JOIN dbo.TB_ATTR2_ENTRIES
                                ON ( dbo.TB_SKUS.ATTR2_ENTRY_ID = dbo.TB_ATTR2_ENTRIES.ATTR2_ENTRY_ID )
                                -- TB_ATTR2_ENTRIES.ATTR2_ENTRY_ID IS "NOT NULL". THEREFORE NO NEED TO CHECK FOR NULLS.

                                -- VW_TB_TERM_SALE_ENTRIES ATTR1_ENTRY_ID CAN BE NULL. ALSO ATTR2 ENTRY ID LIKEWISE.

                                LEFT OUTER JOIN
                                dbo.VW_TB_TERM_SALE_ENTRIES
                                ON dbo.VW_TB_TERM_SALE_ENTRIES.STYLE_ID = dbo.TB_STYLES.STYLE_ID 
                                -- STYLE_ID IS NEVER NULL IN TB_TERM_SALE_ENTRIES IN A SELECT STATEMENT WHERE STYLE_ID IS NULL
                                -- dbo.TB_STYLES.STYLE_ID CAN NOT BE NULL. THEREFORE IT IS OF NO CONSEQUENCE IF THE OTHER IS NULL.
                                AND (dbo.VW_TB_TERM_SALE_ENTRIES.ATTR1_ENTRY_ID = dbo.TB_SKUS.ATTR1_ENTRY_ID)                         
                                AND  dbo.VW_TB_TERM_SALE_ENTRIES.ATTR2_ENTRY_ID = dbo.TB_SKUS.ATTR2_ENTRY_ID
                                -- AND dbo.TB_SKU_BUCKETS.STORE_ID = dbo.VW_TB_TERM_SALE_ENTRIES.STORE_ID -- STORE_ID IS FREQUENTLY NULL

                                WHERE dbo.TB_STYLES.WEB_PRODUCT = 'Y' AND
                                dbo.TB_SKU_BUCKETS.STORE_ID = 1 AND
                                dbo.TB_SKUS.SKU_OF3 IS NULL
                                AND dbo.TB_SKUS.ATTR1_ENTRY_ID IS NOT NULL
                                AND dbo.TB_SKUS.ATTR2_ENTRY_ID IS NOT NULL

-- BEGINNING OF PORTION 2 OF UNION ALL
                                UNION ALL
                                SELECT dbo.TB_STYLES.BRAND, dbo.TB_STYLES.STYLE ,
                                dbo.TB_STYLES.[DESCRIPTION], dbo.TB_STYLES.WEB_PRODUCT,
                                dbo.TB_SKU_BUCKETS.QOH, dbo.TB_SKU_BUCKETS.PRICE,
                                dbo.TB_SKU_LOOKUPS.[LOOKUP] AS UPC_CODE, TB_SKU_BUCKETS.AVG_COST,
                                dbo.VW_TB_TERM_SALE_ENTRIES.AMOUNT AS TERM_SALE_ENTRIES_AMOUNT,
                                dbo.VW_TB_TERM_SALE_ENTRIES.ROUNDING AS TERM_SALE_ENTRIES_ROUNDING,
                                dbo.VW_TB_TERM_SALE_ENTRIES.TYP AS TERM_SALE_ENTRIES_TYP,
                                dbo.VW_TB_TERM_SALE_ENTRIES.STYLE_ID
                                -- DELETE THIS ENTRY NEXT TO REVERT BACK TO ORIGINAL:
                                --INTO #TEMP_CURSOR_1_RESULTS
                                --,
                                -- dbo.TB_SKUS.SKU_OF3
                                FROM dbo.TB_STYLES
                                INNER JOIN dbo.TB_SKUS
                                ON dbo.TB_STYLES.STYLE_ID = dbo.TB_SKUS.STYLE_ID
                                INNER JOIN dbo.TB_SKU_BUCKETS
                                ON dbo.TB_SKUS.SKU_ID = dbo.TB_SKU_BUCKETS.SKU_ID
                                INNER JOIN dbo.TB_SKU_LOOKUPS
                                ON (
                                dbo.TB_SKUS.SKU_ID = dbo.TB_SKU_LOOKUPS.SKU_ID
                                -- isnull(dbo.TB_SKUS.SKU_ID, -999)
                                -- =
                                -- isnull(dbo.TB_SKU_LOOKUPS.SKU_ID, -999)
                                )
                                LEFT OUTER JOIN dbo.TB_ATTR1_ENTRIES
                                ON  (dbo.TB_SKUS.ATTR1_ENTRY_ID = dbo.TB_ATTR1_ENTRIES.ATTR1_ENTRY_ID)
                                LEFT OUTER JOIN dbo.TB_ATTR2_ENTRIES
                                ON ( dbo.TB_SKUS.ATTR2_ENTRY_ID = dbo.TB_ATTR2_ENTRIES.ATTR2_ENTRY_ID )

                                LEFT OUTER JOIN
                                dbo.VW_TB_TERM_SALE_ENTRIES
                                ON dbo.VW_TB_TERM_SALE_ENTRIES.STYLE_ID = dbo.TB_STYLES.STYLE_ID -- STYLE_ID IS NEVER NULL IN TB_TERM_SALE_ENTRIES
                                -- AND (dbo.VW_TB_TERM_SALE_ENTRIES.ATTR1_ENTRY_ID = dbo.TB_SKUS.ATTR1_ENTRY_ID)                         
                                AND  dbo.VW_TB_TERM_SALE_ENTRIES.ATTR2_ENTRY_ID = dbo.TB_SKUS.ATTR2_ENTRY_ID
                                -- AND dbo.TB_SKU_BUCKETS.STORE_ID = dbo.VW_TB_TERM_SALE_ENTRIES.STORE_ID -- STORE_ID IS FREQUENTLY NULL

                                WHERE dbo.TB_STYLES.WEB_PRODUCT = 'Y' AND
                                dbo.TB_SKU_BUCKETS.STORE_ID = 1 AND
                                dbo.TB_SKUS.SKU_OF3 IS NULL
                                AND dbo.TB_SKUS.ATTR1_ENTRY_ID IS NULL
                                AND dbo.TB_SKUS.ATTR2_ENTRY_ID IS NOT NULL
-- BEGINNING OF 3RD UNION ALL SECTION
                                UNION ALL
                                SELECT dbo.TB_STYLES.BRAND, dbo.TB_STYLES.STYLE ,
                                dbo.TB_STYLES.[DESCRIPTION], dbo.TB_STYLES.WEB_PRODUCT,
                                dbo.TB_SKU_BUCKETS.QOH, dbo.TB_SKU_BUCKETS.PRICE,
                                dbo.TB_SKU_LOOKUPS.[LOOKUP] AS UPC_CODE, TB_SKU_BUCKETS.AVG_COST,
                                dbo.VW_TB_TERM_SALE_ENTRIES.AMOUNT AS TERM_SALE_ENTRIES_AMOUNT,
                                dbo.VW_TB_TERM_SALE_ENTRIES.ROUNDING AS TERM_SALE_ENTRIES_ROUNDING,
                                dbo.VW_TB_TERM_SALE_ENTRIES.TYP AS TERM_SALE_ENTRIES_TYP,
                                dbo.VW_TB_TERM_SALE_ENTRIES.STYLE_ID
                                -- DELETE THIS ENTRY NEXT TO REVERT BACK TO ORIGINAL:
                                --INTO #TEMP_CURSOR_1_RESULTS
                                --,
                                -- dbo.TB_SKUS.SKU_OF3
                                FROM dbo.TB_STYLES
                                INNER JOIN dbo.TB_SKUS
                                ON dbo.TB_STYLES.STYLE_ID = dbo.TB_SKUS.STYLE_ID
                                INNER JOIN dbo.TB_SKU_BUCKETS
                                ON dbo.TB_SKUS.SKU_ID = dbo.TB_SKU_BUCKETS.SKU_ID
                                INNER JOIN dbo.TB_SKU_LOOKUPS
                                ON (
                                dbo.TB_SKUS.SKU_ID = dbo.TB_SKU_LOOKUPS.SKU_ID
                                -- isnull(dbo.TB_SKUS.SKU_ID, -999)
                                -- =
                                -- isnull(dbo.TB_SKU_LOOKUPS.SKU_ID, -999)
                                )
                                LEFT OUTER JOIN dbo.TB_ATTR1_ENTRIES
                                ON  (dbo.TB_SKUS.ATTR1_ENTRY_ID = dbo.TB_ATTR1_ENTRIES.ATTR1_ENTRY_ID)
                                LEFT OUTER JOIN dbo.TB_ATTR2_ENTRIES
                                ON ( dbo.TB_SKUS.ATTR2_ENTRY_ID = dbo.TB_ATTR2_ENTRIES.ATTR2_ENTRY_ID )

                                LEFT OUTER JOIN
                                dbo.VW_TB_TERM_SALE_ENTRIES
                                ON dbo.VW_TB_TERM_SALE_ENTRIES.STYLE_ID = dbo.TB_STYLES.STYLE_ID -- STYLE_ID IS NEVER NULL IN TB_TERM_SALE_ENTRIES
                                AND (dbo.VW_TB_TERM_SALE_ENTRIES.ATTR1_ENTRY_ID = dbo.TB_SKUS.ATTR1_ENTRY_ID)                         
                                -- AND  dbo.VW_TB_TERM_SALE_ENTRIES.ATTR2_ENTRY_ID = dbo.TB_SKUS.ATTR2_ENTRY_ID
                                -- AND dbo.TB_SKU_BUCKETS.STORE_ID = dbo.VW_TB_TERM_SALE_ENTRIES.STORE_ID -- STORE_ID IS FREQUENTLY NULL

                                WHERE dbo.TB_STYLES.WEB_PRODUCT = 'Y' AND
                                dbo.TB_SKU_BUCKETS.STORE_ID = 1 AND
                                dbo.TB_SKUS.SKU_OF3 IS NULL
                                AND dbo.TB_SKUS.ATTR1_ENTRY_ID IS NOT NULL
                                AND dbo.TB_SKUS.ATTR2_ENTRY_ID IS NULL
-- BEGINNING OF 4TH UNION ALL SECTION
                                UNION ALL
                                SELECT dbo.TB_STYLES.BRAND, dbo.TB_STYLES.STYLE ,
                                dbo.TB_STYLES.[DESCRIPTION], dbo.TB_STYLES.WEB_PRODUCT,
                                dbo.TB_SKU_BUCKETS.QOH, dbo.TB_SKU_BUCKETS.PRICE,
                                dbo.TB_SKU_LOOKUPS.[LOOKUP] AS UPC_CODE, TB_SKU_BUCKETS.AVG_COST,
                                dbo.VW_TB_TERM_SALE_ENTRIES.AMOUNT AS TERM_SALE_ENTRIES_AMOUNT,
                                dbo.VW_TB_TERM_SALE_ENTRIES.ROUNDING AS TERM_SALE_ENTRIES_ROUNDING,
                                dbo.VW_TB_TERM_SALE_ENTRIES.TYP AS TERM_SALE_ENTRIES_TYP,
                                dbo.VW_TB_TERM_SALE_ENTRIES.STYLE_ID
                                -- DELETE THIS ENTRY NEXT TO REVERT BACK TO ORIGINAL:
                                --INTO #TEMP_CURSOR_1_RESULTS
                                --,
                                -- dbo.TB_SKUS.SKU_OF3
                                FROM dbo.TB_STYLES
                                INNER JOIN dbo.TB_SKUS
                                ON dbo.TB_STYLES.STYLE_ID = dbo.TB_SKUS.STYLE_ID
                                INNER JOIN dbo.TB_SKU_BUCKETS
                                ON dbo.TB_SKUS.SKU_ID = dbo.TB_SKU_BUCKETS.SKU_ID
                                INNER JOIN dbo.TB_SKU_LOOKUPS
                                ON (
                                dbo.TB_SKUS.SKU_ID = dbo.TB_SKU_LOOKUPS.SKU_ID
                                -- isnull(dbo.TB_SKUS.SKU_ID, -999)
                                -- =
                                -- isnull(dbo.TB_SKU_LOOKUPS.SKU_ID, -999)
                                )
                                LEFT OUTER JOIN dbo.TB_ATTR1_ENTRIES
                                ON  (dbo.TB_SKUS.ATTR1_ENTRY_ID = dbo.TB_ATTR1_ENTRIES.ATTR1_ENTRY_ID)
                                LEFT OUTER JOIN dbo.TB_ATTR2_ENTRIES
                                ON ( dbo.TB_SKUS.ATTR2_ENTRY_ID = dbo.TB_ATTR2_ENTRIES.ATTR2_ENTRY_ID )

                                LEFT OUTER JOIN
                                dbo.VW_TB_TERM_SALE_ENTRIES
                                ON dbo.VW_TB_TERM_SALE_ENTRIES.STYLE_ID = dbo.TB_STYLES.STYLE_ID -- STYLE_ID IS NEVER NULL IN TB_TERM_SALE_ENTRIES
                                -- AND (dbo.VW_TB_TERM_SALE_ENTRIES.ATTR1_ENTRY_ID = dbo.TB_SKUS.ATTR1_ENTRY_ID)                         
                                -- AND  dbo.VW_TB_TERM_SALE_ENTRIES.ATTR2_ENTRY_ID = dbo.TB_SKUS.ATTR2_ENTRY_ID
                                -- AND dbo.TB_SKU_BUCKETS.STORE_ID = dbo.VW_TB_TERM_SALE_ENTRIES.STORE_ID -- STORE_ID IS FREQUENTLY NULL

                                WHERE dbo.TB_STYLES.WEB_PRODUCT = 'Y' AND
                                dbo.TB_SKU_BUCKETS.STORE_ID = 1 AND
                                dbo.TB_SKUS.SKU_OF3 IS NULL
                                AND dbo.TB_SKUS.ATTR1_ENTRY_ID IS NULL
                                AND dbo.TB_SKUS.ATTR2_ENTRY_ID IS NULL


                                """)
...