оба запроса должны дать мне один и тот же результат - SQL - PullRequest
0 голосов
/ 08 марта 2019

** Здравствуйте, я пытаюсь найти количество возвращающихся и новых клиентов за определенный период времени. У меня есть два запроса, один для того, чтобы просто найти новых и постоянных клиентов, а другой - тот же, но делит данные на возрастной диапазон и их пол. Технически оба запроса должны давать одинаковые итоги, но они имеют разные итоги. Ниже приведен вопрос, может кто-нибудь объяснить мне, в чем проблема, я действительно с этим борюсь.

Также общее количество совпадений в образце базы данных, которое я создал, но не совпадает в моей фактической базе данных. **

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

https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=be7e1aec30f03edeb0cce246ff05721f

Ниже приведен запрос только для получения новых и постоянных клиентов:

новый клиент

SELECT
    DECODE(is_new, 1, 'New Customers', 'Returning Customers') type_of_customer,
    COUNT(distinct individual_id) count_of_customers,
    SUM(count_of_transactions) count_of_transactions,
    SUM(sum_of_quantity) sum_of_quantity
FROM (
    SELECT
    individual_id,
    SUM(dollar_value_us),
    sum(quantity) sum_of_quantity,
    count(distinct transaction_number) count_of_transactions,
    CASE WHEN MIN(txn_date) = min_txn_date THEN 1 ELSE 0 END is_new
FROM (
    SELECT 
        individual_id, 
        dollar_value_us,
        txn_date,
        quantity,
        transaction_number,
        MIN(txn_date) OVER(PARTITION BY individual_id) min_txn_date          
    FROM transaction_detail_mv   
    WHERE 
        brand_org_code = 'BRAND'
        AND is_merch = 1
        AND currency_code = 'USD'
        AND line_item_amt_type_cd = 'S'
)
WHERE 
    txn_date >= TO_DATE('10-02-2019', 'DD-MM-YYYY') 
    AND txn_date < TO_DATE('17-02-2019', 'DD-MM-YYYY')
GROUP BY
    individual_id,
    min_txn_date
    )
x GROUP BY is_new

ниже - это запрос, который делит те же данные выше по возрасту и полу, но у меня есть два отдельных запроса для новых и постоянных клиентов.

для нового клиента запрос:

select gender, 
case when age < 18 then '<18'
when age between 18 and 24 then '18-24'
when age between 25 and 32 then '25-32'
when age between 33 and 39 then '35-39'
when age between 40 and 46 then '40-46'
when age between 47 and 53 then '46-52'
when age between 54 and 60 then '53-58'
when age > 60 then '61+' end as AgeGroup
, count(distinct individual_id) indiv
, count (distinct transaction_number) txn_count
, sum(dollar_value_us) as Spend
, sum(quantity) Qty

from (SELECT 
        a.individual_id, 
        a.dollar_value_us,
        a.txn_date,
        a.quantity,
        a.transaction_number,
        b.gender,
        b.age,
        MIN(txn_date) OVER(PARTITION BY a.individual_id) min_txn_date          
    FROM transaction_detail_mv   a
    join gender_details b on a.individual_id = b.individual_id
    WHERE 
        a.brand_org_code = 'BRAND'
        AND a.is_merch = 1
        AND a.currency_code = 'USD'
        AND a.line_item_amt_type_cd = 'S')

where txn_date >= TO_DATE('10-02-2019', 'DD-MM-YYYY') 
    AND txn_date < TO_DATE('17-02-2019', 'DD-MM-YYYY')
    AND min_txn_date >= TO_DATE('10-02-2019', 'DD-MM-YYYY')
    AND min_txn_date < TO_DATE('17-02-2019', 'DD-MM-YYYY')


group by gender, 
case when age < 18 then '<18'
when age between 18 and 24 then '18-24'
when age between 25 and 32 then '25-32'
when age between 33 and 39 then '35-39'
when age between 40 and 46 then '40-46'
when age between 47 and 53 then '46-52'
when age between 54 and 60 then '53-58'
when age > 60 then '61+' end

для постоянных клиентов:

select gender, 
case when age < 18 then '<18'
when age between 18 and 24 then '18-24'
when age between 25 and 32 then '25-32'
when age between 33 and 39 then '35-39'
when age between 40 and 46 then '40-46'
when age between 47 and 53 then '46-52'
when age between 54 and 60 then '53-58'
when age > 60 then '61+' end as AgeGroup
, count(distinct individual_id) indiv
, count (distinct transaction_number) txn_count
, sum(dollar_value_us) as Spend
, sum(quantity) Qty

from (SELECT 
        a.individual_id, 
        a.dollar_value_us,
        a.txn_date,
        a.quantity,
        a.transaction_number,
        b.gender,
        b.age,
        MIN(txn_date) OVER(PARTITION BY a.individual_id) min_txn_date          
    FROM transaction_detail_mv   a
    join gender_details b on a.individual_id = b.individual_id
    WHERE 
        a.brand_org_code = 'BRAND'
        AND a.is_merch = 1
        AND a.currency_code = 'USD'
        AND a.line_item_amt_type_cd = 'S')

where txn_date >= TO_DATE('10-02-2019', 'DD-MM-YYYY') 
    AND txn_date < TO_DATE('17-02-2019', 'DD-MM-YYYY')
    AND min_txn_date <TO_DATE('10-02-2019', 'DD-MM-YYYY')


group by gender, 
case when age < 18 then '<18'
when age between 18 and 24 then '18-24'
when age between 25 and 32 then '25-32'
when age between 33 and 39 then '35-39'
when age between 40 and 46 then '40-46'
when age between 47 and 53 then '46-52'
when age between 54 and 60 then '53-58'
when age > 60 then '61+' end

1 Ответ

2 голосов
/ 08 марта 2019

Убедитесь, что вы сравниваете целые даты в своих WHERE предложениях. Если в данные попадает значение времени, вы можете получить противоречивые результаты.

Обновите пункты WHERE для новых клиентов:

where TRUNC(txn_date) >= TO_DATE('10-02-2019', 'DD-MM-YYYY')
    AND TRUNC(txn_date) < TO_DATE('17-02-2019', 'DD-MM-YYYY')
    AND TRUNC(min_txn_date) >= TO_DATE('10-02-2019', 'DD-MM-YYYY')
    AND TRUNC(min_txn_date) < TO_DATE('17-02-2019', 'DD-MM-YYYY')

А ваши постоянные клиенты будут:

where TRUNC(txn_date) >= TO_DATE('10-02-2019', 'DD-MM-YYYY')
    AND TRUNC(txn_date) < TO_DATE('17-02-2019', 'DD-MM-YYYY')
    AND TRUNC(min_txn_date) <TO_DATE('10-02-2019', 'DD-MM-YYYY')

Я также рекомендую реорганизовать ваши запросы, чтобы не смешивать код на основе строк с кодом на основе наборов. Другими словами, выполняйте построчную обработку в операторах подзапросов / WITH, а затем агрегирование. Это значительно облегчит понимание и поддержку SQL.

Пример 1 - Новые клиенты

SELECT
t.gender,
t.AgeGroup,
count(distinct t.individual_id) as indiv,
count(distinct t.transaction_number) as txn_count,
sum(t.dollar_value_us) as Spend,
sum(t.quantity) as Qty
from (
        SELECT
        a.individual_id,
        a.dollar_value_us,
        a.txn_date,
        a.quantity,
        a.transaction_number,
        b.gender,
        b.age,
        case
            when b.age < 18 then '<18'
            when b.age between 18 and 24 then '18-24'
            when b.age between 25 and 32 then '25-32'
            when b.age between 33 and 39 then '35-39'
            when b.age between 40 and 46 then '40-46'
            when b.age between 47 and 53 then '46-52'
            when b.age between 54 and 60 then '53-58'
            when b.age > 60 then '61+'
        end as AgeGroup,
        MIN(a.txn_date) OVER (PARTITION BY a.individual_id) as min_txn_date
        FROM transaction_detail_mv a
        inner join gender_details b on b.individual_id = a.individual_id
        WHERE a.brand_org_code = 'BRAND'
        AND a.is_merch = 1
        AND a.currency_code = 'USD'
        AND a.line_item_amt_type_cd = 'S'
    ) t
where TRUNC(t.txn_date) >= TO_DATE('10-02-2019', 'DD-MM-YYYY')
AND TRUNC(t.txn_date) < TO_DATE('17-02-2019', 'DD-MM-YYYY')
AND TRUNC(t.min_txn_date) >= TO_DATE('10-02-2019', 'DD-MM-YYYY')
AND TRUNC(t.min_txn_date) < TO_DATE('17-02-2019', 'DD-MM-YYYY')
group by t.gender,
         t.AgeGroup;

Пример 2 - Возвращение клиентов

select
t.gender,
t.AgeGroup,
count(distinct individual_id) as indiv,
count (distinct transaction_number) as txn_count,
sum(dollar_value_us) as Spend,
sum(quantity) as Qty
from (
        SELECT
        a.individual_id,
        a.dollar_value_us,
        a.txn_date,
        a.quantity,
        a.transaction_number,
        b.gender,
        b.age,
        case
            when b.age < 18 then '<18'
            when b.age between 18 and 24 then '18-24'
            when b.age between 25 and 32 then '25-32'
            when b.age between 33 and 39 then '35-39'
            when b.age between 40 and 46 then '40-46'
            when b.age between 47 and 53 then '46-52'
            when b.age between 54 and 60 then '53-58'
            when b.age > 60 then '61+'
        end as AgeGroup,
        MIN(txn_date) OVER(PARTITION BY a.individual_id) as min_txn_date
        FROM transaction_detail_mv a
        inner join gender_details b on b.individual_id = a.individual_id
        WHERE a.brand_org_code = 'BRAND'
        AND a.is_merch = 1
        AND a.currency_code = 'USD'
        AND a.line_item_amt_type_cd = 'S'
    ) t
where TRUNC(t.txn_date) >= TO_DATE('10-02-2019', 'DD-MM-YYYY')
AND TRUNC(t.txn_date) < TO_DATE('17-02-2019', 'DD-MM-YYYY')
AND TRUNC(t.min_txn_date) <TO_DATE('10-02-2019', 'DD-MM-YYYY')
group by t.gender,
         t.AgeGroup;
...