SQL:如何使用函数返回视图

时间:2017-03-28 07:24:33

标签: mysql sql

我有一个pdo预处理语句,我想在我的数据库中创建一个视图。 "问题"是它需要一个参数。

我从this answer获取灵感,但我似乎无法让它正常工作。使用原始语句,我得到了所有相关的文章,但是下面的函数/视图示例返回所有文章,无论我将@ p1设置为。

我原来的陈述:

SELECT DISTINCT a.articleTitle, a.articlePermalink
FROM articles a
JOIN articleKeywords ak ON a.idarticles = ak.articleId
JOIN articleKeywords ak2 ON ak.keywordId = ak2.keywordId
    AND ak2.articleId = :articleId
    AND NOT (a.idarticles = :articleId);

其中:articleId是通过PHP给出的参数。

我创建了一个返回整数的函数:

CREATE FUNCTION p1() RETURNS INTEGER DETERMINISTIC NO SQL RETURN @p1;

我的观点:

CREATE VIEW `view_articleRelated` AS
    SELECT DISTINCT a.articleTitle, a.articlePermalink
    FROM articles a
    JOIN articleKeywords ak ON a.idarticles = ak.articleId
    JOIN articleKeywords ak2 ON ak.keywordId = ak2.keywordId
        AND ak2.articleId = p1()
        AND NOT (a.idarticles = p1());

最后,使用p1()

从视图中进行选择
SELECT s.* FROM (SELECT @p1:=123 p) foo, view_articleRelated s;

enter image description here

3 个答案:

答案 0 :(得分:1)

在我的第一个答案中,示例代码中存在一些拼写错误和其他一些问题。

我从查询中涉及的ERD创建了三个表:

DROP TABLE IF EXISTS `articles`;
CREATE TABLE `articles` (
    `idarticles`            INT(10) UNSIGNED        NOT NULL    AUTO_INCREMENT                  COMMENT 'Primary Key',
    `articleTitle`          VARCHAR(60)             NULL,
    `articlePermalink`      VARCHAR(60)             NULL,
    `articleBody`           TEXT                    NULL,
    `articleAuthor`         INT(10)                 NULL,
    `createdAt`             DATETIME                NULL,
    `updatedAt`             DATETIME                NULL,
    PRIMARY KEY (`idarticles`),
    KEY `idx_articles1` (`articleTitle`)
)
    ENGINE=MyISAM 
    AUTO_INCREMENT=1 
    DEFAULT CHARSET=utf8 
    COLLATE=utf8_unicode_ci
    COMMENT 'List of Articles';


DROP TABLE IF EXISTS `articleKeywords`;
CREATE TABLE `articleKeywords` (
    `idarticleKeywords`     INT(10) UNSIGNED        NOT NULL    AUTO_INCREMENT                  COMMENT 'Primary Key',
    `articleId`             INT(10)                 NULL,
    `keywordId`             INT(10)                 NULL,
    PRIMARY KEY (`idarticleKeywords`),
    KEY `idx_articlekeywords1` (`articleId`),
    KEY `idx_articlekeywords2` (`keywordId`)
)
    ENGINE=MyISAM 
    AUTO_INCREMENT=1 
    DEFAULT CHARSET=utf8 
    COLLATE=utf8_unicode_ci
    COMMENT 'Linking table between Articles and Keywords';


DROP TABLE IF EXISTS `keywords`;
CREATE TABLE `keywords` (
    `idkeywords`            INT(10) UNSIGNED        NOT NULL    AUTO_INCREMENT                  COMMENT 'Primary Key',
    `keyword`               VARCHAR(45)             NULL,
    PRIMARY KEY (`idkeywords`)
)
    ENGINE=MyISAM 
    AUTO_INCREMENT=1 
    DEFAULT CHARSET=utf8 
    COLLATE=utf8_unicode_ci
    COMMENT 'List of Keywords';

然后用一些示例数据填充它们:

INSERT INTO `keywords`
(`idkeywords`,`keyword`)
VALUES
(1,'Travel'),
(2,'Hotels'),
(3,'Boats'),
(4,'Cars'),
(5,'Trucks'),
(6,'Pack Animals');

INSERT INTO `articles`
(`idarticles`,`articleTitle`,`articlePermalink`,`articleBody`,`articleAuthor`,`createdAt`,`updatedAt`)
VALUES
(1,'Article 1','http://www.123.com/1','Some text goes here for article',1,'2017/03/28 04:10:00','2017/03/28 04:10:00'),
(2,'Article 2','http://www.123.com/2','Some more text goes here for article',3,'2017/03/28 04:10:00','2017/03/28 04:10:00'),
(3,'Article 3','http://www.123.com/3','Some other text goes here for article',2,'2017/03/28 04:10:00','2017/03/28 04:10:00'),
(4,'Article 4','http://www.123.com/4','Some even more text goes here for article',1,'2017/03/28 04:10:00','2017/03/28 04:10:00');

INSERT INTO `articleKeywords`
(`idarticleKeywords`,`articleId`,`keywordId`)
VALUES
(1,1,2),
(2,1,3),
(3,2,1),
(4,2,4),
(5,3,2),
(6,3,5),
(7,4,2),
(8,4,3),
(9,2,5);

然后我测试了插入数据之间的关系:

SELECT 
    a1.`idarticles` as `baseArticleId`, 
    a2.`idarticles` as `relatedArticleId`, 
    a2.`articleTitle` as `articleTitle`,
    a2.`articlePermalink` as `articlePermalink`
FROM `articles` a1
JOIN `articleKeywords` ak1
    ON a1.`idarticles` = ak1.`articleId`
JOIN `articleKeywords` ak2
    ON ak1.`keywordId` = ak2.`keywordId`
    AND ak1.`articleId` <> ak2.`articleId`
JOIN `articles` a2
    ON a2.`idarticles` = ak2.`articleId`
    AND a2.`idarticles` <> a1.`idarticles`
GROUP BY a1.`idarticles`,a2.`idarticles`,a2.`articleTitle`,a2.`articlePermalink`;

输出:

baseArticleId relatedArticleId articleTitle     articlePermalink
1   3   Article 3   http://www.123.com/3
1   4   Article 4   http://www.123.com/4
2   3   Article 3   http://www.123.com/3
3   1   Article 1   http://www.123.com/1
3   2   Article 2   http://www.123.com/2
3   4   Article 4   http://www.123.com/4
4   1   Article 1   http://www.123.com/1
4   3   Article 3   http://www.123.com/3

最后,根据上面的示例查询创建了视图:

DROP VIEW IF EXISTS `view_articleRelated`;

CREATE VIEW `view_articleRelated` AS
    SELECT 
        a1.`idarticles` as `baseArticleId`, 
        a2.`idarticles` as `relatedArticleId`, 
        a2.`articleTitle` as `articleTitle`,
        a2.`articlePermalink` as `articlePermalink`
    FROM `articles` a1
    JOIN `articleKeywords` ak1
        ON a1.`idarticles` = ak1.`articleId`
    JOIN `articleKeywords` ak2
        ON ak1.`keywordId` = ak2.`keywordId`
        AND ak1.`articleId` <> ak2.`articleId`
    JOIN `articles` a2
        ON a2.`idarticles` = ak2.`articleId`
        AND a2.`idarticles` <> a1.`idarticles`
    GROUP BY a1.`idarticles`,a2.`idarticles`,a2.`articleTitle`,a2.`articlePermalink`;

这里正在使用:

SELECT *
FROM `view_articleRelated`
WHERE `baseArticleId` = 1;

返回第3和第4条。

SELECT *
FROM `view_articleRelated`
WHERE `baseArticleId` = 2;

返回第3条。

SELECT *
FROM `view_articleRelated`
WHERE `baseArticleId` = 3;

返回第1,第2和第4条。

SELECT *
FROM `view_articleRelated`
WHERE `baseArticleId` = 4;

返回第1和第3条。

答案 1 :(得分:0)

@Brian Emilius,试试这个:

SELECT 
    a.idarticles as `article_id`, 
    a2.articleTitle, 
    a2.articlePermalink
FROM articles a
JOIN articleKeywords ak 
    ON a.idarticles = ak.articleId
JOIN articleKeywords ak2
    ON ak.keyword = ak2.keyword
    AND ak.articleId <> a.idarticles
JOIN articles a2
    ON a2.idarticles = ak2.articleId
    AND a2.articleId <> a.idarticles
WHERE a.idarticles = 123
GROUP BY a2.idarticles;

FROM查找参考文章。第一个连接获取该文章的关键字列表。第二个连接查找其他文章的匹配关键字记录。最后一个联接使用相同的关键字查找文章(不包括参考文章)。

如果可行,则使用除WHERE子句之外的所有内容创建视图。

CREATE VIEW `view_articleRelated` AS
    SELECT 
        a.idarticles as `article_id`, 
        a2.articleTitle, 
        a2.articlePermalink
    FROM articles a
    JOIN articleKeywords ak 
        ON a.idarticles = ak.articleId
    JOIN articleKeywords ak2
        ON ak.keyword = ak2.keyword
        AND ak.articleId <> a.idarticles
    JOIN articles a2
        ON a2.idarticles = ak2.articleId
        AND a2.articleId <> a.idarticles
    GROUP BY a2.idarticles;

然后使用视图:

SELECT *
FROM `view_articleRelated`
WHERE `article_id` = 123;

答案 2 :(得分:0)

我们正在寻找与此特定文章共享关键字的其他文章::articleId

select other.articleTitle, other.articlePermalink
from articles this
join articles other on other.articleId <> this.articleId
where exists
(
  select keywordId 
  from articleKeywords
  where articleId in (this.idarticles, other.idarticles)
  group by keywordId
  having sum(articleId = this.idarticles) > 0 -- keyword occurs in :articleId
     and sum(articleId = other.idarticles) > 0 -- keyword occurs in the other article
)
where this.idarticles = :articleId;

相应地创建视图。我们不是将视图本身限制在articleId,而是选择articleId,然后可以在查询中应用where子句:

create view view_articleRelated as
select this.idarticles as articleId, other.articleTitle, other.articlePermalink
from articles this
join articles other on other.articleId <> this.articleId
where exists
(
  select keywordId 
  from articleKeywords
  where articleId in (this.idarticles, other.idarticles)
  group by keywordId
  having sum(articleId = this.idarticles) > 0 -- keyword occurs in :articleId
     and sum(articleId = other.idarticles) > 0 -- keyword occurs in the other article
);

查询:

select articleTitle, articlePermalink
from view_articleRelated
where articleId = :articleId;