SQL: Count and subquery

Viewed 101

Again with count and sql

on sqlite, I have the tables

  • papers: paper_id, doi, year
  • writtenby: paper_id, author_id, inst_id
  • authors: author_id, name, firstname
  • inst: inst_id, name, see_id

inst is a table of Institutions: Universities and so on. Each line in writtenby gives a paper, an author, an institution this author was attached at that time. There can be more then one institution and the couple paper_id, author_id is repeated for each institution. For a given author, I want a list and of papers.doi, papers.year and the count of cohautors he has written a paper with. I tried

 SELECT  papers.doi, papers.year, count(*) as c
 FROM authors 
 INNER JOIN writtenby ON authors.author_id =  writtenby.author_id
 INNER JOIN writtenby AS writtenby_1 ON writtenby.paper_id =  
 writtenby_1.paper_id
 INNER JOIN papers on  writtenby_1.paper_id = papers.paper_id 
 WHERE authors.name ='Beck' AND authors.firstname= 'H P' 
 GROUP BY papers.doi, papers.year
 ORDER BY c DESC

The problem I'm having could be that if the author I'm searching with appears twice for a given paper (because of two institutions) the count is doubled. For a given paper the expected result of 2890, is given by the number of rows of

SELECT DISTINCT author_id
FROM writtenby 
WHERE paper_id = 4593 

(with my data: 2890 rows) Without distinct, I would have 3023 rows, and the first query above gives 6046 for count. I tried to use DISTINCT in the Count clause above but that still does not work.

Can I use count with a subquery ? Thanks for any help...

Sample Data:

-- Make the tables

CREATE TABLE 'authors' (name collate nocase, firstname collate nocase, see_id integer, 'author_id' INTEGER PRIMARY KEY NOT NULL );
CREATE TABLE 'inst' ('name' TEXT NOT NULL, 'country' TEXT NOT NULL , 'see_id' INTEGER, 'inst_id' INTEGER PRIMARY KEY NOT NULL );
CREATE TABLE 'papers' ('doi' TEXT NOT NULL,'year' TEXT NOT NULL, 'paper_id' INTEGER PRIMARY KEY NOT NULL );
CREATE TABLE 'writtenby' ('paper_id' INTEGER NOT NULL, 'author_id' INTEGER NOT NULL, 'inst_id' INTEGER NOT NULL, PRIMARY KEY ('paper_id', 'author_id', 'inst_id'));

-- Insert the data 

-- authors : 5 names, one with 2 variants

INSERT INTO 'authors' (name, firstname, see_id, author_id) VALUES ('Doe', 'J', 1, 1);
INSERT INTO 'authors' (name, firstname, see_id, author_id) VALUES ('Klein', 'K', 2, 2);
INSERT INTO 'authors' (name, firstname, see_id, author_id) VALUES ('Lang', 'F', 3, 3);
INSERT INTO 'authors' (name, firstname, see_id, author_id) VALUES ('Rue', 'A De La', 6, 4);
INSERT INTO 'authors' (name, firstname, see_id, author_id) VALUES ('La Rue', 'A De', 6, 5);
INSERT INTO 'authors' (name, firstname, see_id, author_id) VALUES ('De La Rue', 'A', 6, 6);
INSERT INTO 'authors' (name, firstname, see_id, author_id) VALUES ('Smith', 'S', 7, 7);

-- inst 4 name, 2 variants

INSERT INTO 'inst' (name, country, see_id, inst_id) VALUES ('Universite de Paris', 'France', 1, 1);
INSERT INTO 'inst' (name, country, see_id, inst_id) VALUES ('Paris University', 'France', 1, 2);
INSERT INTO 'inst' (name, country, see_id, inst_id) VALUES ('Universite de Lyon', 'France', 3, 3);
INSERT INTO 'inst' (name, country, see_id, inst_id) VALUES ('Univ Freiburg', 'Germany', 4, 4);
INSERT INTO 'inst' (name, country, see_id, inst_id) VALUES ('EPFZ', 'Switzerland', 5, 5);
INSERT INTO 'inst' (name, country, see_id, inst_id) VALUES ('Eidg Techn Hochschule', 'Switzerland', 5, 6);

-- papers: 3 papers

INSERT INTO 'papers' (doi, year, paper_id) VALUES ('doi1', '2017', 1);
INSERT INTO 'papers' (doi, year, paper_id) VALUES ('doi2', '2018', 2);
INSERT INTO 'papers' (doi, year, paper_id) VALUES ('doi3', '2018', 3);

-- paper 1: 4 authors

INSERT INTO 'writtenby' (paper_id, author_id,  inst_id) VALUES (1, 6, 1);
INSERT INTO 'writtenby' (paper_id, author_id,  inst_id) VALUES (1, 6, 3);
INSERT INTO 'writtenby' (paper_id, author_id,  inst_id) VALUES (1, 1, 5);
INSERT INTO 'writtenby' (paper_id, author_id,  inst_id) VALUES (1, 2, 4);
INSERT INTO 'writtenby' (paper_id, author_id,  inst_id) VALUES (1, 7, 1);

-- paper 2: 3 authors

INSERT INTO 'writtenby' (paper_id, author_id,  inst_id) VALUES (2, 6, 1);
INSERT INTO 'writtenby' (paper_id, author_id,  inst_id) VALUES (2, 6, 3);
INSERT INTO 'writtenby' (paper_id, author_id,  inst_id) VALUES (2, 1, 5);
INSERT INTO 'writtenby' (paper_id, author_id,  inst_id) VALUES (2, 2, 5);

-- paper 3: 3 authors

INSERT INTO 'writtenby' (paper_id, author_id,  inst_id) VALUES (3, 6, 1);
INSERT INTO 'writtenby' (paper_id, author_id,  inst_id) VALUES (3, 2, 4);
INSERT INTO 'writtenby' (paper_id, author_id,  inst_id) VALUES (3, 6, 3);
INSERT INTO 'writtenby' (paper_id, author_id,  inst_id) VALUES (3, 2, 1);
INSERT INTO 'writtenby' (paper_id, author_id,  inst_id) VALUES (3, 3, 4);
INSERT INTO 'writtenby' (paper_id, author_id,  inst_id) VALUES (3, 3, 5);
INSERT INTO 'writtenby' (paper_id, author_id,  inst_id) VALUES (3, 3, 1);

Check the queries:

 SELECT  papers.doi, papers.year, count(*) as c
 FROM authors 
 INNER JOIN writtenby ON authors.author_id =  writtenby.author_id
 INNER JOIN writtenby AS writtenby_1 ON writtenby.paper_id =  
 writtenby_1.paper_id
 INNER JOIN papers on  writtenby_1.paper_id = papers.paper_id 
 WHERE authors.name ='De La Rue' AND authors.firstname= 'A' 
 GROUP BY papers.doi, papers.year
 ORDER BY c DESC


SELECT p.doi, p.year, COUNT(w2.author_id) AS cnt
FROM authors a
INNER JOIN writtenby w1
    ON a.author_id =  w1.author_id
INNER JOIN writtenby w2
    ON w1.paper_id = w2.paper_id AND w1.author_id <> w2.author_id
INNER JOIN papers p
    ON w2.paper_id = p.paper_id 
WHERE
    a.name = 'De La Rue' AND a.firstname = 'A'
GROUP BY
    p.doi, p.year
ORDER BY
    cnt DESC;

Both queries gives wrong results First one:

doi3|2018|14
doi1|2017|10
doi2|2018|8

Second query

doi3|2018|10
doi1|2017|6
doi2|2018|4

François

2 Answers

One counting problem I see is happening is in your self-join of the writtenby table. There, you are not checking that the matching row has a different author_id. If the author_id be the same, then you should not be counting it. Also, what you should be counting for the number of shared authors is the second writtenby table. This way, should a given author not have any coauthors, the count would show up as zero.

SELECT p.doi, p.year, COUNT(w2.author_id) AS cnt
FROM authors a
INNER JOIN writtenby w1
    ON a.author_id =  w1.author_id
INNER JOIN writtenby w2
    ON w1.paper_id = w2.paper_id AND w1.author_id <> w2.author_id
INNER JOIN papers p
    ON w2.paper_id = p.paper_id 
WHERE
    a.name = 'Beck' AND a.firstname = 'H P'
GROUP BY
    p.doi, p.year
ORDER BY
    cnt DESC;

With the help of Tim Biegeleisen and the sample data, I found that what was missing is the clause DISTINCT in the count

SELECT p.doi, p.year, COUNT(DISTINCT w2.author_id) AS cnt
FROM authors a
INNER JOIN writtenby w1
ON a.author_id =  w1.author_id
INNER JOIN writtenby w2
ON w1.paper_id = w2.paper_id 
INNER JOIN papers p
ON w2.paper_id = p.paper_id 
WHERE
a.name = 'De La Rue' AND a.firstname = 'A'
GROUP BY
p.doi, p.year
ORDER BY
cnt DESC;

give the total number of authors.

doi1    2017    4
doi2    2018    3
doi3    2018    3

Withe the clause w1.author_id <> w2.author_id, the count is reduced by one.

F.

Related