复杂的SQL查询,不知道从哪里开始

时间:2016-01-28 16:36:12

标签: sql-server tsql

我认为我在这里很难受。我有以下表格:

[Assets]
AssetId | Name              
1       | Acura NSX
2       | Dodge Ram

[Assignments]
AssignmentId | AssetId | StartMileage | EndMileage | StartDate | EndDate
1            | 1       | 8000         | 10000      | 4/1/2015  | 5/1/2015
2            | 1       | 10000        | 16000      | 9/15/2015 | 1/5/2016
3            | 2       | 51000        | NULL       | 1/1/2016  | NULL

[Reminders]
ReminderId | AssetId | Name          | Distance    | Time      | Active
1          | 1       | Oil Change    | 3000 (miles)| 3 (months)| 1
2          | 1       | Tire Rotation | 5000        | 6         | 0
3          | 2       | Oil Change    | 3000        | 3         | 1
4          | 2       | Air Filter    | 50000       | 48        | 1

[Maintenance]
MaintenanceId | AssetId | ReminderId | Mileage   | Date     | Vendor
1             | 1       | 1          | 10000     | 5/1/2015 | Jiffy Lube
2             | 2       | 3          | 51000     | 6/1/2015 | Dealership

我需要一个将加入这4个表并返回如下内容的查询。

Name      | Name          | Current Mileage | Last Mileage | Last Date
Acura NSX | Oil Change    | 16000           | 10000        | 5/1/2015
Dodge RAM | Oil Change    | 51000           | 51000        | 6/1/2015
Dodge RAM | Air Filter    | 51000           | --           | --

我需要从Reminders表中取出距离阈值并将其添加到Maintenance表中的里程数,然后将其与Assignments表中的起始里程和结束里程进行比较。如果阈值大于开始或结束里程,则选择资产名称,提醒名称,当前里程(分配的开始或结束里程,以较大者为准),以及上次提醒的里程和日期。我需要为时间阈值做同样的事情。将其添加到维护表中的日期,然后将其与今天的日期进行比较。如果它更大,则显示资产。

你们其中一位SQL专家可以帮我解决这个问题吗?

更新:

SELECT
    v.Name,
    r.Name AS Reminder,
    a.CurrentMileage,
    i.MaintenanceMileage,
    i.MaintenanceDate
FROM
    Assets v
LEFT JOIN
    (SELECT AssetId,
            COALESCE(EndMileage, StartMileage) AS CurrentMileage,
            ROW_NUMBER() OVER (PARTITION BY AssetId
                               ORDER BY AssignmentId DESC) AS window_id
    FROM Assignments) a
    ON v.AssetId = a.AssetId
    AND a.window_id = 1
JOIN
    Reminders r
    ON v.AssetId = r.AssetId
    AND r.ActiveFlag = 1
LEFT JOIN
    (SELECT AssetId,
            ReminderId,
            MAX(Mileage) AS MaintenanceMileage,
            MAX([Date]) AS MaintenanceDate
    FROM Maintenances
    GROUP BY AssetId, ReminderId) i
    ON r.ReminderId = i.ReminderId
    AND (a.CurrentMileage > (NULLIF(i.MaintenanceMileage, 0) + r.DistanceThreshold))
    OR (GETDATE() > DATEADD(m, r.[TimeThreshold], i.MaintenanceDate))

1 个答案:

答案 0 :(得分:1)

这是一个起点:

<resources>
<!-- This was my generated key -->
    <string name="google_maps_key" templateMergeStrategy="preserve" translatable="false">MY********KEY</string>
</resources>

日期计算稍微过于简单,因为它们使用最新的分配日期。您真正想要的是一列SELECT v.Name AS [Asset Name], r.Name AS Reminder, a.CurrentMileage, m.Mileage + r.Distance AS [Last Mileage], m.[Date] AS [Last Date] FROM Assets v JOIN ( -- get the latest relevant row as window_id = 1 SELECT AssetId, COALESCE(EndMileage, StartMileage) AS CurrentMileage, COALESCE(EndDate, StartDate) AS AssignDate, ROW_NUMBER() OVER (partition by AssetId order by COALESCE(EndDate, StartDate) DESC) AS window_id FROM Assignments ) a ON v.AssetId = a.AssetId AND a.window_id = 1 JOIN Reminders r ON v.AssetId = r.AssetId AND r.Active = 1 LEFT JOIN Maintenance m ON r.AssetId = m.AssetId AND r.ReminderId = m.ReminderId -- corrected AND ((a.CurrentMileage > (NULLIF(m.Mileage, 0) + r.Distance)) -- slightly oversimplified OR (GETDATE() > DATEADD(m, r.[Time], COALESCE(m.[Date], a.AssignDate)))) ,它将在第一次维护到期之前锚定时间。但这会让你开始。