我有一个Perl程序,它会查询MySQL数据库,根据哪个"报告"用户从网页中选择的选项。
其中一份报告是学生住房大楼的所有住户,他们申请了停车许可证,但尚未获得停车许可证。
当学生申请许可证时,它会在一个表格行中记录他们的汽车(品牌,型号,年份,颜色等)的细节。每间公寓最多可容纳3名学生,每名学生可申请许可。因此,公寓可能有0个许可证,或1,2或3个许可证,具体取决于其中有多少车辆。
我希望能够做的是,执行一个MySQL查询,找出每个公寓中有多少人占用了停车许可证,然后根据该查询的结果找出已发出多少许可证。如果发出的许可证数量少于申请数量,则应在结果集中返回该公寓号码。它不必为特定的占用者命名,只是公寓至少有一名申请许可但尚未获得许可的人。
所以我有两个表,一个叫occupant_info
,它包含有关占用者的各种信息,但相关字段是:
counter (a unique row id)
parking_permit_1_number
parking_permit_2_number
parking_permit_3_number
当指定了停车许可证时,会将其记录在相应的parking_permit_#_number field
中(如果它是第1号乘客的许可证,则会记录在parking_permit_1_number
等中)。
第二个表名为parking_permits
,包含所有汽车/所有者详细信息(品牌,型号,年份,所有者,所有者地址等)。它还包含一个引用occupant_info
表中的计数器的字段。
所以一个例子是:
occupant_info表
counter | parking_permit_1_number | parking_permit_2_number | parking_permit_3_number
--------|-------------------------|-------------------------|------------------------
1 | 12345 | | 98765
2 | 43920 | |
3 | 30239 | | 34233
parking_permits表
counter | counter_from_occupant_info | permit_1_name | permit_2_name | permit_3_name
--------|----------------------------|---------------|-----------------|-------------------
1 |2 | David Jones | James Cameron | Michael Smerconish
2 |3 | Bill Epps | Hillary Clinton | Donald Trump
3 |1 | Joanne Miller | | Sridevi Gupta
我想要一个查询,首先查看公寓中有多少人占用了许可证。这是通过计算parking_permits
表中的名称来确定的。在该表中,第1行有三个名称,第2行有三个名称,第3行有两个名称。然后,查询应查看occupant_info
表,并从counter_from_occupant_info
表中查看每个parking_permits
,查看是否已签发相同数量的停车许可证。这可以通过比较非空白parking_permit_#_number
字段的数量来确定。
使用上面的数据,查询会看到以下内容:
parking_permit table row 1
Has counter_from_occupant_info equal to "2"
Has three names
The row in occupant_info with counter = "2" has only one permit number issued,
so counter_from_occupant_info 2 from parking_permits should be in the result set.
parking_permit table row 2
Has counter_from_occupant_info equal to "3"
Has three names
The row in occupant_info with counter = "3" has only two permit numbers issued,
so counter_from_occupant_info 3 from parking_permits should be in the result set.
parking_permit table row 3
Has counter_from_occupant_info equal to "1"
Has two names
The row in occupant_info with counter = "1" has two permit numbers issued,
so this row should *not* be in the result set.
我已考虑过使用if
,then
,case
,when
,type logic
在一个查询中执行此操作,但坦率地说可以& #39;围绕如何做到这一点。
我在想这样的事情:
SELECT
CASE WHEN ( SELECT counter_from_occupant_info
FROM parking_permits
WHERE parking_permit_1_name != ""
AND parking_permit_2_name != ""
AND parking_permit_3_name != "" ) THEN
IF ( SELECT parking_permit_1_number,
parking_permit_2_number,
parking_permit_3_number
FROM occupant_info
WHERE counter = ***somehow reference counter from above case statement--I don't know how to do this***
然后我的脑袋爆炸了,我意识到我不知道我在做什么。
任何帮助将不胜感激。 : - )
Doug
答案 0 :(得分:1)
你有一些问题:
您的占用者表架构很糟糕。那里的情况更糟,但看起来有些人并不了解数据库的工作原理。
您的许可表也很糟糕。同样的原因。
你不知道自己在做什么(开玩笑......开玩笑......)
问题1:
您的居住者表应该是两张桌子。因为占用者可能有0-3个许可证(可能更多,我无法从样本数据中得知),那么您需要一个表格来显示您的占用者的属性(姓名,身高,性别,年龄,主要气味,最喜欢的颜色,第一次租赁日期,我不知道)。
乘员
OccupantID | favorite TV Show | number of limbs | first name | last name | aptBuilding
并且......占用者和许可证之间关系的另一个表格:
Occupant_permits
OccupantID | Permit ID | status
现在......占用者可以拥有尽可能多的许可证,并且他们之间的关系具有状态"申请"或"授予"或"撤销"或者你有什么。
问题2
你的许可证信息表也是双重职责。它包含有关许可证(它的名称)以及与占用者的关系的信息。因为我们已经与" Occupant_Permits"上面的表格,我们只需要一张许可证表来保存许可证的属性:
许可证
Permit ID | Permit Name | Description | etc..
问题3
现在你有一个正确的架构,其中的对象在他们自己的表中(占用者,许可证,占用者和许可证关系)你的查询得到一个公寓列表,其中至少有一个占用者已经申请但尚未收到许可证将是:
SELECT
COUNT(DISTINCT o.AptBuilding)
FROM
occupants as o
INNER JOIN occupants_permit as op
ON o.occupant_id = op.occupant_id
INNER JOIN permits as p
ON op.permit_id = p.permit_id
WHERE
op.Status = "Applied"
这很简单,你不依赖CASE
或UNION
或计算比较或任何花哨的东西。只是很好的直接连接和一个简单的WHERE子句。这将是快速查询,并没有有趣的业务。
因为您的架构不是很好,为了获得类似的东西,您需要使用UNION查询将许多permit_N_字段堆叠到单个字段中并运行类似于上述查询的内容,或者您将使用相当数量的CASE / IF声明:
SELECT DISTINCT p.pCounter
FROM
(
SELECT
counter as Ocounter
CASE WHEN parking_permit_1_number IS NOT NULL THEN 1 ELSE 0 END
+
CASE WHEN parking_permit_2_number IS NOT NULL THEN 1 ELSE 0 END
+
CASE WHEN parking_permit_3_number IS NOT NULL THEN 1 ELSE 0 END AS permitCount
FROM occupant_info
) as o
LEFT OUTER JOIN
(
SELECT
counter_from_occupant_info as pCounter
CASE WHEN parking_permit_1_name IS NOT NULL THEN 1 ELSE 0 END
+
CASE WHEN parking_permit_2_name IS NOT NULL THEN 1 ELSE 0 END
+
CASE WHEN parking_permit_3_Name IS NOT NULL THEN 1 ELSE 0 END AS permitPermitCount
) as p ON o.Ocounter = p.Pcounter
WHERE p.permitCounter > o.PermitCount
我并非100%确信这正是您正在寻找的,因为您的架构令人困惑,因为您在一个表中有多个对象并且所有内容都是旋转的,但是......它应该让您在球中公园。
这也会慢得多。有中间结果集,CASE语句和数学,所以不要指望MySQL在几毫秒内吐出这个。