我正在努力想出一个网络应用程序,有点像一步一步或程序应用程序。我无法真正描述它并且不知道如何调用它,但它是一个应用程序,它提供了关于如何实现某些内容的逐步指令,如作业应用程序。< / p>
“帮助用户了解如何做事的应用程序。”
所以我设置了一些GUI,现在我面临问题的核心:数据库设置。
在我设计的GUI中,我认为它是这样的:
图例:
如图所示,我在每个程序下有3个顶级程序和其他一些子程序 。该图片中缺少的一件事是顶层程序也属于特定类别。
我想要实现的是跟踪用户的活动。这是交易:
我打算像这样设置我的数据库:
-tbl_users -
id | username | password |
-----------------------------------------
1 | some_user | adf8jkdfndsa |
...
tbl_step_cat
id | cat_name |
---------------------------
1 | some_category |
...
tbl_steps
id | step_shortdesc | step_longdesc | cat_id
-------------------------------------------------------------------
1 | some step one | do the following... | 1
-------------------------------------------------------------------
2 | some step two | do the following... | 1
-------------------------------------------------------------------
3 | some step three | do the following... | 2
...
tbl_substeps
id | substep_shortdesc | substep_longdesc | step_id
-------------------------------------------------------------------
1 | some substep one | do the following... | 1
-------------------------------------------------------------------
2 | some substep two | do the following... | 1
-------------------------------------------------------------------
3 | some substep three | do the following... | 1
-------------------------------------------------------------------
4 | some substep a | do the following... | 2
-------------------------------------------------------------------
5 | some substep b | do the following... | 2
-------------------------------------------------------------------
6 | some substep 1 | do the following... | 3
...
然后是用户和步骤之间的关系表
tbl_user_stepcat
id | user_id | stepcat_id | datetime
-------------------------------------------------------------------
1 | 1 | 1 | sometime
-------------------------------------------------------------------
2 | 1 | 2 | sometime
-------------------------------------------------------------------
tbl_user_step
id | user_id | step_id | datetime
-------------------------------------------------------------------
1 | 1 | 1 | sometime
-------------------------------------------------------------------
2 | 1 | 2 | sometime
-------------------------------------------------------------------
tbl_user_substep
id | user_id | substep_id | datetime
-------------------------------------------------------------------
1 | 1 | 1 | sometime
-------------------------------------------------------------------
2 | 1 | 2 | sometime
-------------------------------------------------------------------
如果这有点长,我很抱歉,这只是因为代码。
现在我的问题是如何返回我想要的结果。如您所见,当用户登录到应用程序时,我希望他/她能够立即查看这些信息。
我从未尝试过这一刻,因为我的大脑刚关闭而且失焦,这是我迄今为止最好的时间。
如果我要编写此应用程序的SQL代码,我将进行多个连接。
我想首先选择所有类别并将其输出给用户。
SELECT * FROM tbl_step_cat
这将为我提供所有类别,接下来我想要做的是找出完成的步骤,以便我可以做'样式'
我可能会这样做
SELECT cat_name FROM tbl_step_cat JOIN
tbl_user_stepcat ON tbl_user_stepcat.stepcat_id = tbl_step_cat.id
...
我没有焦点,现在想不到。我该怎么做:
user = session['user']
非常感谢,我只需要指导。
答案 0 :(得分:5)
好的,如果您只是指定了JOIN,那将是一个内部联接,因此将排除用户尚未完成每个步骤和子步骤的结果。因此,为了确保您可以获得每次加入的结果,我将其设为LEFT JOIN。这可以使用null结果加入它,这很好,因为您可以测试子类别字段是否为null,以便填充表单上的刻度部分。
我一直认为将数据库逻辑拆分成单独的查询并没有什么坏处,而不是试图编写一个将所有内容连接到一切的巨型查询,这可能是过多的。
我想我会对每个类别进行单独查询,即:
(伪)
SELECT * FROM CATEGORIES
foreach (category) {
SELECT * FROM SUBCATEGORIES WHERE CATEGORY = CATEGORYID
foreach (SUBCATEGORY) {
SELECT * FROM SUBSUBCATEGORIES WHERE SUBCATEGORY = SUBCATEGORYID
}
}
在每个点上查询用户表,以查看用户是否在遍历列表时完成了每个步骤,并使用该循环填充您的刻度。
它可能不如单个超级联盟那么优雅,但如果这不是你的事情,我不会看到简化查询逻辑以帮助你理解的任何伤害。
答案 1 :(得分:3)
您不需要表格user_stepcat
和user_step
,因为它们只会存储多余的信息。
每个completed
状态都由子步骤的完成触发,并且可以通过此查询检索
-- cat completed or not
SELECT
sc.*,
MIN( IF( uss.substep_id IS NULL, 0, 1 ) ) completed,
IF( MIN( IF( uss.substep_id IS NULL, 0, 1 ) ),
MAX( uss.datetime ),
NULL ) completed_at
FROM
step_cat sc
LEFT JOIN steps s ON s.cat_id = sc.id
LEFT JOIN substeps ss ON ss.step_id = s.id
LEFT JOIN user_substep uss ON uss.user_id = 1 AND uss.substep_id = ss.id
GROUP BY sc.id;
-- steps completed or not
SELECT
s.*,
MIN( IF( uss.substep_id IS NULL, 0, 1 ) ) completed,
IF( MIN( IF( uss.substep_id IS NULL, 0, 1 ) ),
MAX( uss.datetime ),
NULL ) completed_at
FROM
steps s
LEFT JOIN substeps ss ON ss.step_id = s.id
LEFT JOIN user_substep uss ON uss.user_id = 1 AND uss.substep_id = ss.id
GROUP BY s.id;
-- substeps completed or not
SELECT
ss.*,
IF( uss.substep_id IS NULL, 0, 1 ) completed,
uss.datetime completed_at
FROM
substeps ss
LEFT JOIN user_substep uss ON uss.user_id = 1 AND uss.substep_id = ss.id;
<强>更新强>
为了给你一个更相关的GUI答案我已经更新了样本数据以匹配你的截图。
对于演示文稿,您需要知道当前用户ID,类别ID和步骤ID
SET @user_id = 1; -- actual user
SET @cat_id = 1; -- actual category
SET @step_id = 2; -- actual step
您可以使用
获取当前类别并完成状态SELECT
sc.*,
MIN( IF( uss.substep_id IS NULL, 0, 1 ) ) completed,
IF( MIN( IF( uss.substep_id IS NULL, 0, 1 ) ), MAX( uss.datetime ), NULL ) completed_at
FROM
step_cat sc
LEFT JOIN steps s ON s.cat_id = sc.id
LEFT JOIN substeps ss ON ss.step_id = s.id
LEFT JOIN user_substep uss ON
-- limit to user
uss.user_id = @user_id
AND uss.substep_id = ss.id
-- limit to cat
WHERE sc.id = @cat_id
GROUP BY sc.id;
使用此
的类别步骤和完成状态SELECT
s.*,
MIN( IF( uss.substep_id IS NULL, 0, 1 ) ) completed,
IF( MIN( IF( uss.substep_id IS NULL, 0, 1 ) ), MAX( uss.datetime ), NULL ) completed_at
FROM
steps s
LEFT JOIN substeps ss ON ss.step_id = s.id
LEFT JOIN user_substep uss
-- limit to user_id
ON uss.user_id = @user_id
AND uss.substep_id = ss.id
-- limit to cat_id
WHERE s.cat_id = @cat_id
GROUP BY s.id;
至少子步骤及其完整状态
SELECT
ss.*,
IF( uss.substep_id IS NULL, 0, 1 ) completed,
uss.datetime completed_at
FROM
substeps ss
LEFT JOIN user_substep uss
-- limit to user_id
ON uss.user_id = @user_id
AND uss.substep_id = ss.id
-- limit to step_id
WHERE ss.step_id = @step_id;
通过所有这3个查询,您可以获得GUI演示所需的所有信息。
答案 2 :(得分:1)
您现在可能过分关注数据库结构:
然后,您可以减少数据库结构,同时保持更灵活,也更容易重用成就系统的程序。
例如,如果你决定有一天你想要创建一个成就,如果有人已经完成你所谓的 stepcat 的整个类别,如果我正确地读了你的问题。
您需要做的就是检查一个或 n 成就是否已经完成。因此,无论是否包含其他成就,都要将所有成就保留在一个表中。这属于其他地方。与类别相同。
一种常见的方法是对数据进行部分去标准化,例如:你可以保留一些自由文本与每个成就,以存储一些因素处理可以使用的数据。
运行janitor作业以保持数据顺序,同时检查您是否错过了检查更高阶的某些成就。无论如何,您需要这样做,因为在您处理时引入错误的第一刻,即使在完全规范化的形式中您也不会违反任何约束,您的数据也会被破坏。因此,无论如何你都需要进行“手动”检查。
由于所有这些,只需这样做。不要把头包住太多,保持简单,完成工作,然后你可以考虑改进它。我能给出的第一个建议就是保持简单,这样你就不会犯很多错误。您的系统将具有此处无法解决的专业。
所以你需要的只是:
虽然:
是否是一个多步骤并不是真的很有趣。这只是一个标准的成就。这将是最大的好处。将差异封装到处理中,而不是数据结构中。这将允许您现在和将来采用。
答案 3 :(得分:1)
您的意思是您的SQL架构看起来像step_cat&lt; - steps&lt; - substeps?
如果是这样,表tbl_user_stepcat和tbl_user_step是无用的,因为您可以使用JOIN查询从给定的子步骤/步骤/猫获取所有父信息。
如果您想要关注用户成就,您应该只有一个“achievement_history”表,重点关注用户,子步和定义的状态,这可能会根据其成就采取特定值。 这样每条线指的是给定的用户子步骤成就,然后每当给定的子步骤具有正确的成就状态时,用户将能够处理另一个子步骤并且将插入新的行。
请记住,使用嵌套查询是这种丑陋的方式继续,因为DBMS永远无法规划查询,并且可能存储预定义的方式来获得应有的快速结果,如果设置正确,则使用索引和外键。
答案 4 :(得分:1)
你必须在后端编写3个存储过程并使用前端的输入Session [Username]调用它们。
storedprocedure1 .. listofcategories ..输入 - 无,输出 - 类别属性
storedprocedure2 .. listofcategories_filtered_by_user ..输入 - 会话[用户名]输出 - 类别属性
在这个存储过程中写下你写的SELECT cat_name FROM tbl_step_cat JO的接合tbl_user_stepcat ON tbl_user_stepcat.stepcat_id = tbl_step_cat.id
storedprocedure3 .. listofsubcategories_filtered_by_user .. input- Session [UserName] output-(sub category attributes)
在此存储过程内写入子类别的连接
<强>&GT;现在使用输入从前端调用每个Storedprocedure 会话[用户名]参数