SQL-запрос, чтобы показать, что было выплачено каждый месяц - PullRequest
1 голос
/ 18 апреля 2010

Мне нужна помощь для создания запроса, чтобы решить следующую проблему:

Давайте представим строку:

Name    StartDate   EndDate     Paid
James   10-10-2010  17-02-2011  860

И вот схема для таблицы в соответствии с запросом:

payment_details (name VARCHAR(50) NOT NULL, 
                 start_date DATETIME NOT NULL, 
                 end_date DATETIME NOT NULL,
                 paidFLOAT NOT NULL)

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

Name    Year    Month   Paid
James   2010    10      172
James   2010    11      172
James   2010    12      172
James   2011    01      172
James   2011    02      172

Существует множество разных клиентов с разными StartDate / EndDate и уплаченной суммой, поэтому запрос должен с этим справиться. Как я могу сделать это в SQL (MS SQL Server 2005)?

Помощь будет высоко ценится!

Ответы [ 4 ]

3 голосов
/ 18 апреля 2010

Вам необходимо:

  • создать строку для каждого месяца для каждого имени (используйте таблицу чисел)
  • генерирует разницу месяцев как делитель (DATEDIFF использует конец месяца в качестве границы месяца)
  • предположим, end_date> = start_date (есть ли у вас ограничение CHECK?), Чтобы избежать деления на ноль ошибок

Возможно, вам придется настроить это, конечно ...

--DROP TABLE #numbers 
--DROP TABLE #payment_details
CREATE TABLE #numbers (num smallint PRIMARY KEY)

CREATE TABLE #payment_details (name VARCHAR(50) NOT NULL, 
                 start_date DATETIME NOT NULL, 
                 end_date DATETIME NOT NULL,
                 paid FLOAT NOT NULL)

INSERT #payment_details VALUES ('James', '20101010', '20110217', 860)
INSERT #payment_details VALUES ('Jane', '20101110', '20110117', 900)
INSERT #payment_details VALUES ('John', '20101128', '20101128', 500)

INSERT #numbers
SELECT TOP 1000
    ROW_NUMBER() OVER (ORDER BY c1.object_id) -1
FROM
    sys.columns c1 CROSS JOIN sys.columns c2

SELECT
    P.name,
    DATEPART(year, DATEADD(month, N.Num, start_date)),
    DATEPART(month, DATEADD(month, N.Num, start_date)),
    P.paid / (DATEDIFF(month, start_date, end_date) + 1)
FROM
    #payment_details P
    JOIN
    #numbers N ON DATEDIFF(month, start_date, end_date) >= N.num
1 голос
/ 18 апреля 2010

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

select p.name, d.year, d.month, p.paid/(datediff(m, p.startdate, p.enddate) + 1)
from (
    select year(date) as year, month(date) as month, min(date) as monthbegin, max(date) as monthend
    from datestable
    group by year(date), month(date)
) d
left join payment_detail p on d.monthbegin<p.enddate and d.monthend>p.startdate

Надеюсь, я правильно понял условия соединения, не стесняйтесь исправлять (у меня нет возможности проверить здесь).

0 голосов
/ 18 апреля 2010

Просто, чтобы предложить побочное мышление, вам нужно подряд на каждый месяц? В зависимости от того, рассчитываете ли вы, скажем, что-то из этого, или вы создаете отчет для того, чтобы кто-то его просмотрел, вам может не потребоваться создавать 6 строк, в которых единственными данными являются месяц / год. Это также предполагает, что платежи равномерно распределены по месяцам. Это можно легко написать, выбрав имя, начальный год, начальный месяц, конечный год, конечный месяц, а затем разделив общую сумму выплат ((разница в году * 12) + разница в месяце), чтобы определить ежемесячный платеж.

В зависимости от использования, что-то в этом роде может выглядеть чище и занимать гораздо меньше бумаги, если кто-то собирается его распечатать. :)

0 голосов
/ 18 апреля 2010

Единственный способ, которым я могу видеть это в прямом SQL, - это иметь другую таблицу под названием Periods, содержащую все годы и месяцы, как показано ниже:

Year    Month
2010      10
2010      11
2010      12
2011       1
2011       2
2011       3
2011       4

и так далее ...

Теперь вы присоединяете свою таблицу платежных данных к этой таблице следующим образом:

SELECT PD.[name], Per.Year, Per.Month, 
    PD.payed / DateDiff(mm, PD.start_date, PD.end_date) AS Payed
FROM payment_details PD
    INNER JOIN Periods Per On 
        Per.Year >= DatePart(yy, start_date) AND Per.Month >= DatePart(mm, start_date)
    AND Per.Year <= DatePart(yy, end_date) AND Per.Month <= DatePart(mm, end_date)
ORDER BY PD.[name], Per.Year, Per.Month

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...