【问题标题】:SQL Questions on generating a new table [closed]关于生成新表的 SQL 问题 [关闭]
【发布时间】:2013-03-26 02:16:22
【问题描述】:

图片显示了我的表的结构。第一行表示tutorB 给studentD 10 分。第二行表示tutorE还没有给studentD打分。

如何生成下表?我在 stackoverflow.com 中引用了另一篇文章。 Collaborative filtering in MySQL? 不过,我还是很迷茫。

从上图中,o表示推荐,大于等于7; x表示不推荐,小于7。

例如,tutorB 给 studentD 10 分,因此,从图片的第二行,我们可以看到 StudentD 列有一个“o”。 (其他三行数据现在只是随机分配。)

现在,如果我想为导师 A 推荐一个学生。导师 B、C 和 D 的等级(或相似度)分别为 0,2 和 3。

如何生成 SQL,以便能够将比率转换为“o”和“x”并计算排名。而且,最重要的是,我想从图片中向 TutorA 推荐 StudentH。

我应该如何修改上一篇文章中的代码?而且,如果我上面提到的想法正确?

谢谢。

================================================ ==============================

已编辑

我在数据库中有以下数据。第一行表示 10 分是导师 A 给学生 C 的。

我将其转换为另一个表格以便更好地理解。 v 是速率的值。

create temporary table ub_rank as 
select similar.NameA,count(*) rank
from tbl_rating target 
join tbl_rating similar on target.NameB= similar.NameB and target.NameA != similar.NameA
where target.NameA = "tutorA"
group by similar.NameA;

select similar.NameB, sum(ub_rank.rank) total_rank
from ub_rank
join ub similar on ub_rank.NameA = similar.NameA 
left join ub target on target.NameA = "tutorA" and target.NameB = similar.NameB
where target.NameB is null
group by similar.NameB
order by total_rank desc;

select * from ub_rank;

以上代码引用自Collaborative filtering in MySQL?。我有几个问题。

  1. SQL 中有 2 个部分。我可以从第一部分中选择 *。但是,如果我如上图输入整个SQL,系统会提示Table 'mydatabase.ub' doesn't exist如何修改代码?

  2. 代码会发现相似之处。我应该如何更改代码,如果标记小于7,则更改为o,否则更改为v,并计算给定用户的相似度?

【问题讨论】:

  • 表格中的最后一行是什么意思?这是StudentD给TutorB的“评分”吗?另外,你的桌子上有多少学生?您真的想要为每个现有学生提供一个专栏吗?
  • @BellevueBob 是的,就是StudentD给TutorB的“评分”。上面的第二张图片显示了推荐学生部分,我使用了与第一张图片前两行相似的数据。另一方面,当我执行 Recommendating Tutors 部分时,我将使用 DB 表数据的第三行到最后一行的数据。对于学生的数量,我还没有考虑好。我想我会先尝试弄清楚表格,然后再尝试限制大小。

标签: mysql sql


【解决方案1】:

无耻地借用this previous question的答案,看看这能不能解决问题:

SET @sql = NULL;
SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'max(case when NameB = ''',
      NameB,
      ''' then (case when rate >= 7 then ''x'' else ''o'' end) else '' '' end) AS ',
      replace(NameB, ' ', '')
    )
  ) INTO @sql
from tbl_rating
where RoleA = 'Tutor';

SET @sql = CONCAT('SELECT NameA, ', @sql, 
' from tbl_rating
where RoleA = ''Tutor''
group by NameA');

PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

这里是a SQL Fiddle

【讨论】:

  • 感谢您的大力帮助!我上面的代码怎么样?
【解决方案2】:

您的数据库架构实际上并不是很容易使用。

这里有一个查询来获得一个详尽的评级表:

SELECT Tutor.Name, Student.Name, 
  CASE WHEN Rating.Rate IS NULL THEN ''
    WHEN Rating.Rate > 6 THEN 'o'
    ELSE 'x' END
FROM (
    SELECT DISTINCT NameB AS Name
    FROM tbl_rating 
    WHERE RoleB='Tutor'
    UNION
    SELECT DISTINCT NameA AS Name
    FROM tbl_rating
    WHERE RoleA='Tutor'
    ORDER BY Name) AS Tutor
CROSS JOIN (
    SELECT DISTINCT NameB AS Name
    FROM tbl_rating 
    WHERE RoleB='Student'
    UNION
    SELECT DISTINCT NameA AS Name
    FROM tbl_rating
    WHERE RoleA='Student'
    ORDER BY Name) AS Student
LEFT JOIN tbl_rating AS Rating
ON Tutor.Name = Rating.NameA
AND Student.Name = Rating.NameB
ORDER BY Tutor.Name, Student.Name

上述查询的工作原理是从表中提取所有导师的列表(第一个子查询别名为Tutor)和所有学生的列表(第二个子查询Student),对两组进行乘积以获得所有导师和学生的可能组合。然后与评分表进行外连接,关联查找学生对导师的所有评分,并填写NULL不存在的评分。 (获取相反评分的查询——即导师对学生的评分——可以通过在LEFT JOIN子句中交换NameANameB来获得)。 CASE 根据要求将数字(或空)评级转换为符号。

为了相似之处,我们需要再添加两个连接:

  • 还有一个Tutor
  • 另一个在Rating

因此给予:

SELECT T1.Name AS Tutor1 , T2.Name AS Tutor2, 
  SUM( CASE
    WHEN (R1.Rate > 6 && R2.Rate > 6) || 
                (R1.Rate < 7 && R2.Rate < 7) THEN 1
    ELSE 0 END) AS SIMILARITY
FROM (
    SELECT DISTINCT NameB AS Name
    FROM tbl_rating 
    WHERE RoleB='Tutor'
    UNION
    SELECT DISTINCT NameA AS Name
    FROM tbl_rating
    WHERE RoleA='Tutor'
    ORDER BY Name) AS T1
CROSS JOIN (
    SELECT DISTINCT NameB AS Name
    FROM tbl_rating 
    WHERE RoleB='Tutor'
    UNION
    SELECT DISTINCT NameA AS Name
    FROM tbl_rating
    WHERE RoleA='Tutor'
    ORDER BY Name) AS T2
CROSS JOIN (
    SELECT DISTINCT NameB AS Name
    FROM tbl_rating 
    WHERE RoleB='Student'
    UNION
    SELECT DISTINCT NameA AS Name
    FROM tbl_rating
    WHERE RoleA='Student'
    ORDER BY Name) AS Student
LEFT JOIN tbl_rating AS R1
ON T1.Name = R1.NameA
AND Student.Name = R1.NameB
LEFT JOIN tbl_rating AS R2
ON T2.Name = R2.NameA
AND Student.Name = R2.NameB
WHERE Tutor1 < Tutor2
GROUP BY Tutor1, Tutor2
ORDER BY Tutor1, Tutor2

您可以通过在自己的表中提取学生和导师的特定数据、将评分表拆分为学生评分和导师评分以及使用外键来提高这些查询的效率:

Table student : Id | Name
Table tutor: Id  | Name
Table tutor_rating: StudentId | TutorId | Rate
Table student_rating: StudentId | TutorId | Rate

可能还有一个tutor_similiarity 表,以避免一直重新计算整个数据集,并在评级表上使用几个触发器来更新它(相似性计算将是增量的,查询只会转储其内容)。

Table tutor_similarity: TutorId1 | TutorId2 | Similarity

【讨论】:

  • 我认为我的回答不太正确,关于某处的 JOIN,但我无法在没有测试的情况下查明问题。
  • 不需要使用stackoverflow.com/questions/2440826/… 中提到的“相似”?其实这个方法很适合我的方案,只是我上面修改了一些额外的条件,所以不知道怎么修改。
  • 对不起,我的回答不正确,我明天试试。
【解决方案3】:

这确实是一条评论,但是评论太长了。

首先,您不能轻松地创建具有可变列数的表。你提前知道这些列吗?通常,您以在原始 table 中的方式表示矩阵。 . . “x”和“y”值是列,值位于第三列。

其次,xo 是基于导师对学生的评分,反之亦然?您的问题完全模棱两可。

第三,要将评分转换为“x”或“o”,只需使用 case 语句:

select (case when rating >= 7 then 'x' else 'o' end)

第四,你说A到B、C、D的相似度分别是0、2、3。我不知道你是如何从你展示的矩阵中得到这个的。如果是“x”的重叠,那么这些值似乎是 0、1 和 2。

我的最终结论是,您根本不需要创建这样的矩阵,因为您已经拥有正确格式的数据。

【讨论】:

    猜你喜欢
    • 2011-05-27
    • 2013-10-09
    • 1970-01-01
    • 2012-11-18
    • 2015-07-08
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多