views:

546

answers:

3

How can I define a view that has two calculated fields, for instance...

 ('TableName'.'BlueSquares' + 'TableName'.'RedSquares') AS TotalSquares, ('TableName'.'BlueCirles' + 'TableName'.'RedCircles') AS TotalCircles

... and create a third calculated field that's based on the first two calculated fields, as in...

 ('ViewName'.'TotalSquares' + 'ViewName'.'TotalCircles') AS TotalShapes

...?

When I reference the first two calculated fields by name, I get a message that the fields are unknown.

Thanks!

+1  A: 

Since subqueries are not allowed in views, you will need to simulate them by creating multiple views.

For example, this query will solve your issue if directly executed:

SELECT 
    TotalCircles + TotalSquares AS TotalShapes
FROM
    (SELECT 
     BlueCirles + RedCircles AS TotalCircles,
     BlueSquares + RedSquares AS TotalSquares
    FROM
     (SELECT
      2 AS BlueCirles,
      3 AS RedCircles,
      4 AS BlueSquares,
      5 AS RedSquares
     ) AS shapes
    ) as totals;

According to the MySQL documentation views have the restriction on not being able to contain subqueries in the FROM clause. To work around this limitation and turn this query into a view, break it up into 3 views (one for each subquery) with the last giving the desired combination of fields:

CREATE VIEW shapes AS
SELECT
    2 AS BlueCirles,
    3 AS RedCircles,
    4 AS BlueSquares,
    5 AS RedSquares;

CREATE VIEW totals AS
SELECT 
    BlueCirles + RedCircles AS TotalCircles,
    BlueSquares + RedSquares AS TotalSquares
FROM
    shapes;

CREATE VIEW result AS
SELECT 
    TotalCircles + TotalSquares AS TotalShapes
FROM
    totals;

SELECT * FROM result;
Adam Franco
If you try this, you'll see it causes a SQL error. This is because "The SELECT statement cannot contain a subquery in the FROM clause." See: http://dev.mysql.com/doc/refman/5.0/en/create-view.html
Conspicuous Compiler
I noticed this when I tested my initial answer. I've updated it to use multiple views to simulate subqueries.
Adam Franco
Thanks for putting so much effort into this. I appreciate it.
Alan Neal
+1  A: 

...create a third calculated field that's based on the first two calculated fields...

As you've found, you can't reference computed columns in the same SELECT. Your options are to:

Duplicate the logic

MySQL doesn't support subqueries in views for some odd reason:

CREATE OR REPLACE VIEW your_view AS
SELECT t.BlueSquares + t.RedSquares AS TotalSquares, 
       t.BlueCirles + t.RedCircles AS TotalCircles,
       t.BlueSquares + t.RedSquares + t.BlueCirles + t.RedCircles AS TotalShapes
  FROM TABLE t

Layer the Views

Least recommended option...

 CREATE OR REPLACE VIEW initial_view AS
    SELECT t.BlueSquares + t.RedSquares AS TotalSquares, 
           t.BlueCirles + t.RedCircles AS TotalCircles,
      FROM TABLE

 CREATE OR REPLACE VIEW layered_view AS
    SELECT iv.TotalSquares + iv.TotalCircles AS TotalShapes
      FROM initial_view iv
OMG Ponies
+1  A: 

Unfortunately, what you're trying to do isn't actually possible the way you're doing it. Generally, MySQL views can be viewed as a scripted SELECT. The results of a view aren't stored on the database separate from their source, but are rather calculated when you refer to the view.

Most of the time, MySQL uses the MERGE algorithm when you SELECT from a view. This means it merges the definition of your view and the SELECT statement referring to the view it to create a final SELECT it actually runs. As such, you can't really have a VIEW refer to itself.

Your options here are to (1) define a second view which refers to the first view in order to create your sum, or (2) write out the sum longhand like this:

('TableName'.'BlueSquares' + 'TableName'.'RedSquares' + 'TableName'.'BlueCirles' + 'TableName'.'RedCircles') AS TotalShapes
Conspicuous Compiler