I have created a simple view consisting of 3 tables in SQL.
By right clicking and selecting Design, in the Object explorer table, i modified my custom view. I just added sortby asc in a field.
The problem is that the changes are not reflected in the outout of the View.
After saving the view, and selecting Open view the sort is not displayed in output.
So what is going on here?
Technically, it is possible to bake sorting into a VIEW but it is highly discouraged. Instead, you should apply sort while selecting from the view like so:
Select ...
From MyView
Order By SortByCol ASC
If you really wanted to know (but again, I would strongly recommend against this), you can use the TOP command to get around the limitation of sorting in the view:
Select TOP 100 PERCENT * Col1, Col2....
From Table1
Order By SortByCol ASC
It seems :
There is a restriction on the SELECT clauses in a view definition in SQL Server 2000, SQL 2005 and SQL 2008. A CREATE VIEW statement cannot include ORDER BY clause, unless there is also a TOP clause in the select list of the SELECT statement. The ORDER BY clause is used only to determine the rows that are returned by the TOP clause in the view definition. The ORDER BY clause does not guarantee ordered results when the view is queried, unless ORDER BY is also specified in the query itself.
There is also a hotfix that needs to be applied. After that you should use Top 100% to make sure that the order by works.
HTH
Generally, Views cannot be sorted.
(As others mentioned, there's a hack to do it, but since you are using a visual query designer rather than writing your view definition in SQL, it's probably difficult to implement that hack.)
You didn't actually "modify" your view, you only changed the SELECT statement that EM was using to select from your view. Sort settings are not retained in the view definition.
When you close the tab, EM doesn't remember your sort preference for that view, so when you open the view again, it comes out in whatever order SQL Server decides.
Related
I have view for which it only makes sense to use a certain ordering. What I would like to do is to include the ORDER BY clause in the view, so that all SELECTs on that view can omit it. However, I am concerned that the ordering may not necessarily carry over to the SELECT, because it didn't specify the order.
Does there exist a case where an ordering specified by a view would not be reflected in the results of a select on that view (other than an order by clause in the view)?
You can't count on the order of rows in any query that doesn't have an explicit ORDER BY clause. If you query an ordered view, but you don't include an ORDER BY clause, be pleasantly surprised if they're in the right order, and don't expect it to happen again.
That's because the query optimizer is free to access rows in different ways depending on the query, table statistics, row counts, indexes, and so on. If it knows your query doesn't have an ORDER BY clause, it's free to ignore row order in order (cough) to return rows more quickly.
Slightly off-topic . . .
Sort order isn't necessarily identical across platforms even for well-known collations. I understand that sorting UTF-8 on Mac OS X is particularly odd. (PostgreSQL developers call it broken.) PostgreSQL relies on strcoll(), which I understand relies on the OS locales.
It's not clear to me how PostgreSQL 9.1 will handle this. In 9.1, you can have multiple indexes, each with a different collation. An ORDER BY that doesn't specify a collation will usually use the collation of the underlying base table's columns, but what will the optimizer do with an index that specifies a different collation than an unindexed column in the base table?
Couldn't see how to reply further up. Just adding my reply here.
You can rely on the ordering in every case where you could rely on it if you manually wrote the query.
That's because PostgreSQL rewrites your query merging in the view.
CREATE VIEW v AS SELECT * FROM people ORDER BY surname;
-- next two are identical
SELECT * FROM v WHERE forename='Fred';
SELECT * FROM people WHERE forename='Fred' ORDER BY surname;
However, if you use the view as a sub-query then the sorting might not remain, just as the output order from a sub-query is never maintained.
So - am I saying to rely on this? No, probably better all round to specify your desired sort order in the application. You'll need to do it for every other query anyway. If it's a utility view for DBA use, that's a different matter though - I have plenty of utility views that provide sorted output.
While observations have so far been true for the following, this answer is not definitive by any means. #Catcall and I, both, could not find anything definitive in the documentation and I have to admit, I'm too lazy to wade through and make sense of the source code.
But for observations sake, consider the following:
SELECT * FROM (select * from foo order by bar) foobar;
The query should return ordered.
SELECT * FROM vw_foo; -- where vw_foo is the sub-select above
The query should return ordered.
SELECT * FROM vw_foo LEFT JOIN (select * from bar) bar ON vw_foo.id = bar.id;
The query should use it's own discretion and may return unordered.
Disclaimer:
Much like #Catcall said, you should never truly depend on any implicit sorting, as many times it will be left up to the database engine. Databases are designed for quickness and reliability; they often interface with memory and try to pull/push data as quickly as possible. However, the ordering isn't solely based on memory management, there are several factors that are involved.
Unless you have something specific in mind, you should do your sorting at the end (on the outer query).
If the above observation was true, something like the following should always turn the results in the correct order:
SELECT *
FORM (select trunc(random()*999999+1) as i
from generate_series(1,1000000)
order by i
) foo;
The simple process would be: perform preprocessing and perform query identification (identify that an order exists), start loop, fetch first field (generate random number), add to output stack in sorted order. The ordering may also occur at the end of the stack generation, instead of during (eg compile the list and then do the sorting). This depends on versioning and the query.
My DBA is telling me that it's impossible to have an OrderBy in a SQL view.
I'm having trouble with a 3rd party component that needs to have a view in a particular order. Is this true? Am I not able to sort within a view?
SQL Server views do not honor order bys. There are hacks* to get them to work, but they are undocumented and I'd suggest not depending on them to work correctly in future revisions.
If you want to order a view the correct method for doing so is to put an order by in the select which is reading the view.
This is a commonly misunderstood point of views. So, references: An article, MSDN.
*- order bys are support with the top clause. So, you could, in theory, do a select top 100%. This is wrong. The server does NOT guarantee that the view will remain ordered. This is only supported so you can properly specify exactly which top rows to include. For some queries the order by be kept, but it is entirely a fluke, and if you depend on it you'll have fun tracking down the bug that will eventually pop up when the order is not kept. Ordering of views is not guaranteed.
Ordinarily, SQL Server will object to an ORDER BY in a view. You can cheat a bit by including a TOP clause on your query, which will then allow the ORDER BY.
I would also say: Of cause you can sort select from a view.
But can somebody explain what i find here on msdn?:
The ORDER BY clause is not valid in
views, inline functions, derived
tables, and subqueries, unless TOP is
also specified.
Your DBA is probably worried that you will need or want an indexed view, which slows down inserts and updates.
If I create a view and select my fields in the order I want to "receive" them in can I be fully assured that I can call "Select * from myView" from my apps instead of specifying ALL of the fieldnames yet again in my select query?
I ask this because I pass whole datarows to my DataModels and construct the objects by assigning properties to the different indexes in the itemarray attached to this datarow. If these fields get out of order there's no telling what could happen to my object.
I know that I can't rely on an order-by that lives inside of a view (been burned before on this one). But the order of the fields I was not sure about.
Sorry if this is sql noob level. We all start somewhere with it. Right now all the extraneous field names in my app code is making readability somewhat difficult so if I can safely go back and replace a lot of syntax with a * then that would be great.
These tables are small so i'm not worried about implications of using a * over individual fields. I'm just looking to not code unnecessary syntax.
Column order is guaranteed, row order (as you noted) is not.
Column order may not be guaranteed or reliable if both of these are true
the view definition has SELECT * or SELECT tableA.* internally
any changes are made to the table(s) concerned
You'd need to run sp_refreshview: see this question/answer for potential issues.
Of course, if you have simple SELECT * FROM table in a view, why not just use the table and save some maintenance pain?
Finally, and I have to say it, it isn't recommeded to use SELECT *... :-)
Yes, left-to-right ordering of columns is guaranteed in SQL. In fact, it's one of the top three flaws used to prove that SQL is not truly relational (e.g. see The Importance of Column Names by Hugh Darwen), duplicate rows and the NULL value being the other two.
Yes, I've always relied on select * returning fields in the order specified in the view or table.
For example Microsoft SQL - "* Specifies that all columns from all tables and views in the FROM clause should be returned. The columns are returned by table or view, as specified in the FROM clause, and in the order in which they exist in the table or view."
When I create a view I am basically making a new table that will automatically be transacted upon when data in one of the tables it joins changes; is that correct?
Also why can't I use subqueries in my view?
A view works like a table, but it is not a table. It never exists; it is only a prepared SQL statement that is run when you reference the view name. IE:
CREATE VIEW foo AS
SELECT * FROM bar
SELECT * FROM foo
...is equivalent to running:
SELECT x.*
FROM (SELECT * FROM bar) x
A MySQLDump will never contain rows to be inserted into a view...
Also why can't I use subqueries in my view????
That, sadly, is by (albeit questionable) design. There's numerous limitations for MySQL views, which are documented: http://dev.mysql.com/doc/refman/5.0/en/create-view.html
So if it's just an imaginary table/prepared statement does that mean it theoretically has the same performance (or even less) as a normal table/query?
No.
A table can have indexes associated, which can make data retrieval faster (at some cost for insert/update). Some databases support "materialized" views, which are views that can have indexes applied to them - which shouldn't be a surprise that MySQL doesn't support given the limited view functionality (which only began in v5 IIRC, very late to the game).
Because a view is a derived table, the performance of the view is only as good as the query it is built on. If that query sucks, the performance issue will just snowball... That said, when querying a view - if a view column reference in the WHERE clause is not wrapped in a function (IE: WHERE v.column LIKE ..., not WHERE LOWER(t.column) LIKE ...), the optimizer may push the criteria (called a predicate) onto the original query - making it faster.
I ran into the same problem also (to my surprise, because my search seems to indicate that Oracle and MS do support it).
I get around this limitation (at least for now, until proven non-usable) by creating two additional views for my final view.
Example:
CREATE VIEW Foo1 AS
SELECT * FROM t ORDER BY ID, InsertDate DESC
CREATE VIEW Foo2 AS
SELECT * FROM Foo1 GROUP BY ID
CREATE VIEW Foo AS
SELECT * FROM Foo2 ORDER BY ID
The example above basically has a table 't' which is a temporal table containing all the revisions. My 'Foo' (view) basically is a simple view of only my most current revisions of each record. Seems to work alright for now!
Update:
I don't know if this is another bug in MySQL 5.1, but the above example doesn't in fact work! The 'Foo1' works as expected, but the 'Foo2' seems to ignore the order prior to grouping so my end result is not what is intended. I even get the same result if I change the 'DESC' for 'ASC' (surprisingly).
Also, if you read the 17.5.1. View Syntax section, it clearly states:
"A view can be created from many kinds of SELECT statements. It can refer to base tables or other views. It can use joins, UNION, and subqueries."
I'm going to update my database to 5.6 and try it again!
The difference is :
for view you can only have subqueries in the where - part, not in the from - part so a
CREATE VIEW v AS SELECT * FROM foo WHERE id IN (SELECT id FROM bar)
would work - but at the same time you get a read-only view ... A simple view on a single table would allow to update "through" the view to the underlying table
I'm wondering if this is a bad practice or if in general this is the correct approach.
Lets say that I've created a view that combines a few attributes from a few tables.
My question, what do I need to do so I can query against this view as if it were a table without worrying about performance?
All attributes in the original tables are indexed, my concern is that the result view will have hundreds of thousands of records, which I will want to narrow down quite a bit based on user input.
What I'd like to avoid, is having multiple versions of the code that generates this view floating around with a few extra "where" conditions to facilitate the user input filtering.
For example, assume my view has this header VIEW(Name, Type, DateEntered) this may have 100,000+ rows (possibly millions). I'd like to be able to make this view in SQL Server, and then in my application write querlies like this:
SELECT Name, Type, DateEntered FROM MyView WHERE DateEntered BETWEEN #date1 and #date2;
Basically, I am denormalizing my data for a series of reports that need to be run, and I'd like to centralize where I pull the data from, maybe I'm not looking at this problem from the right angle though, so I'm open to alternative ways to attack this.
My question, what do I need to do so I can query against this view as if it were a table without worrying about performance?
SQL Server is very good in view unnesting.
Your queries will be as efficient as if the view's query were used in the query itself.
This means that
CREATE VIEW myview AS
SELECT *
FROM /* complex joins */
SELECT *
FROM mytable
JOIN myiew
ON …
and
SELECT *
FROM mytable
JOIN (
SELECT *
FROM /* complex joins */
) myview
ON …
will have the same performance.
SQL Server 2005 has indexed views - these provide indexes on views. That should help with performance. If the underlying tables already have good indexes on the queried fields, these will be used - you should only add indexed views when this is not the case.
These are known in other database systems as materialized views.
The view will make use of the index in your WHERE clause to filter the results.
Views aren't stored result sets. They're stored queries, so you'll have the performance gained from your indexes each time you query the view.
Why would it perform badly? I, mean you can think of a view as a compiled select statement. It makes use of existing indexes on the underlying tables, even when you add extra where clauses. In my opinion it is a good approach. In any case it's better than having virtually the same select statement scattered all over your application (from a design and maintainability point of view at least).
If not indexed then...
When you query a view, it's ignored. The view is expanded into the main query.
It is the same as querying the main tables directly.
What will kill you is view on top of view on top of view, in my experience.
It should, in general, perform no worse than the inline code.
Note that it is possible to make views which hide very complex processing (joins, pivots, stacked CTEs, etc), and you may never want anyone to be able to SELECT * FROM view on such a view for all time or all products or whatever. If you have standard filter criteria, you can use an inline table-valued function (effectively a parameterized view), which would require all users to supply the expected parameters.
In your case, for instance, they would always have to do:
SELECT Name, Type, DateEntered
FROM MyITVF(#date1, #date2);
To share the view logic between multiple ITVFs, you can build many inline table-valued functions on top of the view, but not give access to the underlying tables or views to users.