Question

I have 3 talbes: Posts, Pictures and Album. I need to count how many posts, pictures and albums per year were published. Here the creation of the tables:

create table Posts
(
 PostID int primary key identity,
 Description varchar(30) not null,
 Date smalldatetime not null,
 UserWriterID int references Users(UserID)
)

create table Albums
(
 AlbumID int primary key identity,
 Name varchar(20) not null,
 Description varchar(30) not null,
 Date smalldatetime not null,
 AlbumOwnerID int references Users(UserID) 
)

create table Pictures
(
 PictureID int primary key identity,
 AlbumID int references Albums(AlbumID),
 Description varchar(30) not null,
 Date smalldatetime not null,
)

Some data samples from the tables:

Pictures:

PictureID | AlbumID | Desc | Date

    1    |   1   |   aa   | 2000-01-01 00:00:00

    2    |   1   |   bb   | 2011-08-31 15:24:00

    10   |   2   |   d    | 2010-07-17 12:35:00

Albums:

AlbumID | Name |    Desc    |    Date     |      AlbumOwnerID

1   |   My album | my new album |  2000-01-01 00:00:00 |    2

2   |   Belgium trip    | trip in Belgium |  2005-07-08 00:00:00 |  2

9   |    Work   | Work and I  | 2011-07-08 00:00:00  |  11

Posts:

PostID  | Desc | Date | UserWriterID

1  |  Feeling good |    2013-09-10 07:44:00 |  2

2   |  FUN FUN FUN |  2015-12-21 09:45:00  |    8

3   |   Whats up?   | 2014-01-18 12:54:00 |     7 

Then I inserted data.

Now, I writen 3 queries to get per each table the count per year.

create view PostPerYear as
select YEAR(Date) as Year , count(PostID) as Posts
from Posts
group by YEAR(Date)
go 

create view AlbumsPerYear as
select YEAR(Date) as Year , count(AlbumID) as Albums
from Albums 
group by YEAR(Date)
go

create view PicturesPerYear as
select YEAR(Date) as Year , count(PictureID) as Pictures
from Pictures
group by YEAR(Date)
go

But, I need a query that show all the results above TOGETHER. For example:

Year | Posts Count | Albums Count | Pictures Count

2013 | 3 | 4 | 1

2005 | 13 |23 | 5

When I tried I've got cartesian product like:

select (p.Year) , (p.Posts) ,  (a.Albums) , (pic.Pictures)
from PostPerYear p ,AlbumsPerYear a ,PicturesPerYear pic
group by p.Year, p.Posts , a.Albums , pic.Pictures

The result is: Year| Posts | Albums | Pictures

2013    9   1   1

2013    9   1   2

2013    9   1   3

2013    9   1   4

2013    9   1   5

2013    9   1   6

2013    9   1   11

2013    9   2   1

2013    9   2   2

2013    9   2   6

2013    9   2   11

2014    10  1   1

2014    10  1   2

2014    10  1   3

2014    10  1   4

2014    10  1   5

2014    10  1   6

And Continued....
------------------------------
------------------------------

What is the answer PLEASE?

Thanks!

Was it helpful?

Solution

Specifying multiple tables in the FROM clause is equivalent to doing a CROSS JOIN. You can use UNION ALL to solve that problem.

WITH summary(year, posts, albums, pictures) AS (        
    SELECT year, posts, 0, 0 FROM PostsPerYear        
    UNION ALL        
    SELECT year, 0, albums, 0 FROM AlbumsPerYear        
    UNION ALL        
    SELECT year, 0, 0, pictures FROM PicturesPerYear        
)        
SELECT year,        
       sum(posts)    AS posts,        
       sum(albums)   AS albums,        
       sum(pictures) AS pictures        
FROM summary        
GROUP BY year;

OTHER TIPS

First the simplified DDL and some sample data:

create table Posts
(
 PostID int primary key identity,
 Date smalldatetime not null
)

create table Albums
(
 AlbumID int primary key identity,
 Date smalldatetime not null
)

create table Pictures
(
 PictureID int primary key identity,
 Date smalldatetime not null,
)




create view PostPerYear as
select YEAR(Date) as Year , count(PostID) as Posts
from Posts
group by YEAR(Date)
go 

create view AlbumsPerYear as
select YEAR(Date) as Year , count(AlbumID) as Albums
from Albums 
group by YEAR(Date)
go

create view PicturesPerYear as
select YEAR(Date) as Year , count(PictureID) as Pictures
from Pictures
group by YEAR(Date)
go


insert posts values('20130101'), ('20140202')
insert albums values('20130101'), ('20140202'), ('20140202')
insert pictures values('20130101'), ('20130101'), ('20140202')
go

Now, use outer joins (I'd recommend to use ANSI join syntax):

select coalesce(p.Year, a.year, pic.year) as year, p.Posts, a.Albums, pic.Pictures
from PostPerYear p 
full outer join AlbumsPerYear a on p.year = a.year
full outer join PicturesPerYear pic on p.year = pic.year

Returns this:

Year    Posts   Albums  Pictures
2013    1   1   2
2014    1   2   1
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top