我继承了两个表,其中一个数据以小时为单位,另一个数据以天为单位。
一个表计划使用资源,另一个表计算实际花费的时间
Internal_Resources
| PeopleName | NoOfDays | TaskNo |
|------------|----------|--------|
| Fred | 1 | 100 |
| Bob | 3 | 100 |
| Mary | 2 | 201 |
| Albert | 10 | 100 |
TimeSheetEntries
| UserName | PaidHours | TaskNumber |
|----------|-----------|------------|
| Fred | 7 | 100 |
| Fred | 14 | 100 |
| Fred | 7 | 100 |
| Bob | 7 | 100 |
| Bob | 21 | 100 |
| Mary | 7 | 201 |
| Mary | 14 | 100 |
我需要的是计划时间与花费时间的比较。
| name | PlannedDays | ActualDays |
|--------|-------------|------------|
| Albert | 10 | NULL |
| Bob | 3 | 4.00 |
| Fred | 1 | 4.00 |
| Mary | NULL | 2.00 |
我拼凑了几乎可以解决问题的事情:
SELECT
UserName,
( SELECT
NoOfDays FROM Internal_Resources as r
WHERE r.PeopleName = e.UserName AND r.TaskNumber = ? ) AS PlannedDays,
SUM ( Round( PaidHours / 7 , 2 ) ) as ActualDays
FROM TimeSheetEntries e WHERE TaskNo = ?
GROUP BY UserName
对于任务100来说,这给了我类似的东西:
| UserName | PlannedDays | ActualDays |
|----------|-------------|------------|
| Bob | 3 | 4 |
| Fred | 1 | 4 |
| Mary | 0 | 2 |
但是懒惰的阿尔伯特没有特色!我想:
| UserName | PlannedDays | ActualDays |
|----------|-------------|------------|
| Albert | 10 | 0 |
| Bob | 3 | 4 |
| Fred | 1 | 4 |
| Mary | 0 | 2 |
我尝试使用
上的变体SELECT * FROM ( SELECT ... ) AS plan
INNER JOIN ( [second-query] ) AS actual
ON plan.PeopleName = actual.UserName
应该我在做什么?我怀疑我需要在那里挤一个交叉连接,但我无处可去......
(这将在FileMaker ExecuteSQL()调用中运行,所以我需要相当香草的SQL ...而且,不,我无法控制列或表名:-()
编辑:
要明确的是,我需要将结果集包括计划天数和未完成任务的用户,以及那些在没有计划天数的情况下完成任务的人......
编辑2:
我可以手动获得我想要的东西,但无法看到如何组合下面的陈述:
SELECT people.name, PlannedDays, ActualDays FROM
( SELECT PeopleName as name FROM Internal_Resources WHERE TaskNo = 100
UNION
SELECT DISTINCT UserName as name FROM TimeSheetEntries WHERE TaskNumber = 100
ORDER BY Name) AS people
得到我:
+--------+
| name |
+--------+
| Albert |
| Bob |
| Fred |
| Mary |
+--------+
和
( SELECT PeopleName AS name, NoOfDays AS PlannedDays
FROM Internal_Resources WHERE TaskNo = 100 ) AS actual
得到我:
+--------+-------------+
| name | PlannedDays |
+--------+-------------+
| Fred | 1 |
| Bob | 3 |
| Albert | 10 |
+--------+-------------+
最后,
( SELECT UserName AS name, SUM( Round( PaidHours / 7, 2 ) ) AS ActualDays
FROM TimeSheetEntries
WHERE TaskNumber = 100 GROUP BY UserName ) AS planned
得到我:
+------+------------+
| name | ActualDays |
+------+------------+
| Bob | 4.00 |
| Fred | 4.00 |
| Mary | 2.00 |
+------+------------+
现在所有(全部!哈!)我想要将这些结合到这个:
+--------+-------------+------------+
| name | PlannedDays | ActualDays |
+--------+-------------+------------+
| Albert | 10 | NULL |
| Bob | 3 | 4.00 |
| Fred | 1 | 4.00 |
| Mary | NULL | 2.00 |
+--------+-------------+------------+
编辑3:
我尝试将它与以下内容结合起来:
SELECT people.name, PlannedDays, ActualDays
FROM ( SELECT PeopleName as name FROM Internal_Resources WHERE TaskNo = 100
UNION
SELECT DISTINCT UserName as name FROM TimeSheetEntries WHERE TaskNumber = 100
ORDER BY Name) AS people
LEFT JOIN ( SELECT PeopleName AS name, NoOfDays AS PlannedDays FROM Internal_Resources WHERE TaskNo = 100 ) AS actual,
ON people.name = actual.name
LEFT JOIN ( SELECT UserName AS name, SUM( Round( PaidHours / 7, 2 ) ) AS ActualDays FROM TimeSheetEntries WHERE TaskNumber = 100 GROUP BY UserName ) AS planned
ON people.name = planned.name;
但语法显然很不稳定。
答案 0 :(得分:2)
好的 - 这有效:
SELECT people.name, COALESCE(PlannedDays, 0) as planned, COALESCE(ActualDays, 0) as actual
FROM ( SELECT PeopleName as name FROM Internal_Resources WHERE TaskNo = 100
UNION
SELECT DISTINCT UserName as name FROM TimeSheetEntries WHERE TaskNumber = 100
ORDER BY Name) AS people
LEFT JOIN ( SELECT PeopleName AS name, NoOfDays AS PlannedDays FROM Internal_Resources WHERE TaskNo = 100 ) AS ir
ON people.name = ir.name
LEFT JOIN ( SELECT UserName AS name, SUM( Round( PaidHours / 7, 2 ) ) AS ActualDays FROM TimeSheetEntries WHERE TaskNumber = 100 GROUP BY UserName ) AS ts
ON people.name = ts.name;
,并提供:
+--------+---------+--------+
| name | planned | actual |
+--------+---------+--------+
| Albert | 10 | 0.00 |
| Bob | 3 | 4.00 |
| Fred | 1 | 4.00 |
| Mary | 0 | 2.00 |
+--------+---------+--------+
我认为必须有一种更简单的方法,这看起来更简单:
SELECT name, SUM(x) AS planned, SUM(y) AS actual
FROM (
SELECT PeopleName AS name, NoOfDays AS x, 0 AS y
FROM Internal_Resources WHERE TaskNo = 100
UNION
SELECT UserName AS name, 0 AS x, SUM( PaidHours / 7 ) AS y
FROM TimeSheetEntries WHERE TaskNumber = 100 GROUP BY UserName) AS source
GROUP BY name;
但令人沮丧的是 - 无论是在MySQL中工作还是在FileMaker的缩减SQL版本中都失败 - 从派生表中选择似乎不受支持。
最后 - 让它在FileMaker SQL中运行的诀窍 - IN和NOT IN支持子查询...所以三个查询的联合 - 计划好几天并完成一些工作的人,那些做过计划外的人工作,以及没有完成计划工作的人:
SELECT PeopleName as name, NoOfDays as planned, Sum( PaidHours / 7 ) as actual
FROM Internal_Resources
JOIN TimeSheetEntries
ON PeopleName = UserName
WHERE TaskNumber = 100 AND TaskNo = 100 GROUP BY PeopleName
UNION
SELECT UserName as name, 0 as planned, Sum( PaidHours / 7 ) as actual
FROM TimeSheetEntries
WHERE TaskNumber = 100
AND UserName NOT IN (
SELECT PeopleName FROM Internal_Resources WHERE TaskNo = 100
)
UNION
SELECT PeopleName as name, NoOfDays as planned, 0 as actual
FROM Internal_Resources WHERE TaskNo = 100
AND PeopleName NOT IN (
SELECT PeopleName as name
FROM Internal_Resources JOIN TimeSheetEntries
ON PeopleName = UserName
WHERE TaskNumber = 100 AND TaskNo = 100
GROUP BY PeopleName
)
ORDER BY name;
希望这有助于某人。
答案 1 :(得分:1)
反转逻辑以从外部查询中的Internal_resources
读取:
SELECT ir.UserName, NoOfDays as PlannedDays,
(SELECT SUM ( Round( PaidHours / 7 , 2 ))
FROM TimeSheetEntries e
WHERE e.TaskNo = ? AND ir.PeopleName = e.UserName
) as ActualDays
FROM Internal_Resources ir
WHERE ir.TaskNumber = ?
GROUP BY ir.UserName, NoOfDays;
答案 2 :(得分:1)
文件制作者不支持LEFT OUTER JOIN吗?
SELECT
PeopleName,
NoOfDays AS PlannedDays
ROUND(SUM(PaidHours) / 7, 2) AS ActualDays
FROM
Internal_Resources AS planned
-- left join should not discard Albert's record from Internal_Resources
LEFT JOIN TimeSheetEntries AS actual
ON planned.PeopleName = actual.UserName
AND planned.TaskNo = actual.TaskNumber
WHERE
planned.TaskNo = ?
GROUP BY PeopleName, NoOfDays