Rebuild database views - sql

When you create a view, the column structure of the view is created and stored, and thus you can see it in object explorer:
When you alter the source data tables, sometimes things go wacky, because the view may have been built with "Select *" yet the schema created for you has the old information without the additional columns.
Does SQL Server have an easy way to rebuild the view schemas?

Do not use SELECT * in views. I say this as someone who has spent much too much time (in the past) debugging views that had this "feature".
When you do create a view in a production system, create it with SCHEMABINDING:
SCHEMABINDING
Binds the view to the schema of the underlying table or tables. When SCHEMABINDING is specified, the base table or tables cannot be modified in a way that would affect the view definition. The view definition itself must first be modified or dropped to remove dependencies on the table that is to be modified.
Although this adds an extra step when trying to modify tables, the increased resilience of the system is worth it.

Related

Azure / Transact SQL: Dynamically create View of tables with the same name OR add tables after View creation

I'm new to Azure and not great with SQL so any help would be greatly appreciated.
I have a Database where each user has a Schema. Each Schema has identically structured tables with the same name, say "Table".
I now require a View in another Schema which provides a read-only union of all the rows from all the tables Table.
I was successful in creating a Schema, say Views, handling its permissions and creating a View, "TableView", with the following SQL from Partitioned Views # learn.microsoft.com:
CREATE VIEW Views.TableView
AS
SELECT *
FROM Schema1.Table
UNION ALL
SELECT *
FROM Schema2.Table
UNION ALL
SELECT *
FROM Schema3.Table
...
GO
I now wish for this View to be dynamic as future Schemas (SchemaX) are added or even possibly removed without having to repeatedly DROP and CREATE TableView over and over.
Is it possible to create the View in such a way that it would automatically query all tables with the same name? Or perhaps there is some way to 'add' an additional table post creation?
I can get a list of all SchemaX.Table by querying INFORMATION_SCHEMA, but other than having a python script DROP and CREATE the View again I am lost.
Thanks
Thanks for #larnu's comments, it's very useful and professional:
To achieve this dynamically, it would be impossible to do in a VIEW.
You would have to use a stored procedure, and that means you can't do
simple things like SELECT from it, making it far harder to use.
Instead of having 17 tables, all identical, on different schemas you
have one table, with a column BusinessName. Instead of
MySmartCompany.Mytable you have a column in the table dbo.MyTable (or
your generic schema), called BusinessName which has the value 'MySmartCompany'.
This also can be beneficial to other community members.

How do you save a CREATE VIEW statement?

EDIT: This question was based on the incorrect premise that SQL VIEWS were cleared from a database when the user that created them disconnects from the server. Leaving this question in existence in case others have that assumption.
I'm trying to use views in my database, but I'm running up against an inability to save the code as a SQL Server object for repeated use.
I tried saving CREATE VIEW statements as procedures and user defined functions, but as many have answered on stack overflow, CREATE PROCEDURE and CREATE FUNCTION are incompatible with CREATE VIEW due to the only one in batch issue.
Obviously I don't want to retype my CREATE VIEW statements every time, and I'd prefer not to have to load them from text files. I must be missing something here.
You don't really "save" CREATE/ALTER statements. The create or alter statement changes the structure of the database. You can use SSMS to generate the statement again later by right clicking on the view, and choosing Script as->Create. This inspects the structure of the database and generates the statement.
The problem with this approach is your database now consists of both a structure definition(DDL) as well as its contents, the data. If you dropped/created the database to clear its data, you'd also have lost the structure. So you always need a database hanging around for the structure and back it up to ensure you don't ever lose the DDL.
Personally I would use Database Projects as part of Visual Studio and SQL Server Data Tools. This allows you to keep each View, Table, etc. as separate files, and then update the database using schema compare. The main benefit being you can separate the definition of the database from the database itself, and also source control or backup the DDL files.
If you really want to, you could create a view in a proc like this:
CREATE PROCEDURE uspCreateView AS
EXEC('CREATE VIEW... ')
Though, you'll have to escape single quotes in your view code with ''
However, I have to agree with the other comments that this seems like a strange thing to do.
Some other thoughts:
You can use sp_helptext to get the code of an existing view:
sp_helptext '<your view name here>'
Also, INFORMATION_SCHEMA.VIEWS includes a VIEW_DEFINITION column with the same code:
SELECT * FROM INFORMATION_SCHEMA.VIEWS

how to load modified and unmodified data into materialized view in oracle

I have a table T_SG_LTA_TRANSACTION_TYPE in source database.
I want to move it into a target database.
I have created a materialized view log in source database.
CREATE MATERIALIZED VIEW LOG ON T_SG_LTA_TRANSACTION_TYPE WITH PRIMARY KEY, ROWID;
Then I created materialized view in target database with following query.
CREATE MATERIALIZED VIEW T_SG_LTA_TRANSACTION_TYPE
ON PREBUILT TABLE
REFRESH FAST ON DEMAND
FOR UPDATE
AS
SELECT TRANSACTION_ID,
TRANSACTION_DESCRIPTION,
FILE_TYPE_ID
FROM T_SG_LTA_TRANSACTION_TYPE#EBAODWH_SRC_1_GS_AIG;
But when I refresh materialized view , I am unable to load the data which is already present in T_SG_LTA_TRANSACTION_TYPE(SOURCE DB).
BEGIN
DBMS_MVIEW.refresh('T_SG_LTA_TRANSACTION_TYPE');
END;
The data which is updated in source table after creation of materialized view, is only loading to materialized view . But I want to get whole data from source table(modified and unmodified) into materialized view. And I need this unmodified data only once when mview is created. Please suggest the solution. Thanks in advance.
You seem to be using the ON PREBUILT TABLE clause incorrectly:
The ON PREBUILT TABLE clause lets you register an existing table as a preinitialized materialized view.
And
Caution:
This clause assumes that the table object reflects the materialization of a subquery. Oracle strongly recommends that you ensure that this assumption is true in order to ensure that the materialized view correctly reflects the data in its master tables.
You're essentially saying that T_SG_LTA_TRANSACTION_TYPE already exists on the target database - not the source - and contains the current state of the source table; which, since you're missing data, is not true.
When you refresh Oracle is only looking for changes since the view was created, as it's supposed to; it relies on the MV log to identify what has changed.
Drop the MV in the target database, without the preserve table clause, and then recreate it without the on prebuilt table clause.
Make sure you're dropping the right thing in the right database/schema, of course...
It isn't clear if the (empty) table already existed in your target DB before you started; or you've run this a couple of times and dropped the MV with preserve table - and either the source was empty last time, or you truncated the target table afterwards - or perhaps you tried to export/import the initial state but just got the metadata and not the data. If the table you said existed on the target DB did not, in fact, exist then Oracle would have thrown an ORA-12059 exception when you tried to create the MV. I suspect you'd created an empty table and then tried to convert it to an MV, but if you do that it won't get any data from the source DB, as you've seen.

How to keep "*" in VIEW output clause so that columns track table changes?

I'm creating an Oracle view like this :
SELECT * FROM TABLE;
When I create the view, I notice that oracle changes the view query to something like :
SELECT FIELD1, FIELD2,... FROM TABLE;
My problem is that if I change the TABLE structure, add a new field for instance, the changes are not taken into consideration in the view. I have then to recreate the view, and regrant privileges on this view to the users/roles.
Is there any way to make a view mode generic and keep it as the form of : SELECT * FROM TABLE ?
Thanks.
You cannot define a simple view that would automatically change its structure when the underlying table changes. When new columns are added, you'll need to touch the view. You'll almost certainly need to do as #GordonLinoff suggests and do a CREATE OR REPLACE when the table changes. Given that changes to tables should be rare and should involve proper change control, touching the view as part of the change should be a relatively simple step.
If you're really determined to avoid having to touch the view, there are some alternatives. I generally wouldn't recommend these because they are very likely to increase rather than decrease the complexity of maintaining your system. But if you have a third party system that is generating DDL to add columns on an unpredictable basis, maybe it makes sense.
You could create a DDL trigger that fires in response to statements that ALTER the table and that submits a job using dbms_job that re-creates the view. That's quite a few moving pieces but it's generally workable.
Alternately, instead of a view, you could create a pipelined table function that returns a variable number of columns. That's going to be really complicated but it's also pretty slick. There aren't many places that I'd feel comfortable using that approach simply because there aren't many people that can look at that code and have a chance of maintaining it. But the code is pretty slick.
The * is evaluated when the view is created, not when it is executed. In fact, Oracle compiles views for faster execution. It uses the compiled code when the view is referenced. It does not just do a text substitution into the query.
The proper syntax for changing a view is:
create or replace view v_table as
select *
from table;
I have face this same issue and created a procedure which accepts the name of the table and creates the view:
str := 'create or replace view xyz.'|| tablename_in ||'_v as select * from '|| tablename_in;
execute immediate str;
Then in Toad (not sure if you use Toad), in the schema browser, right click on the table name, and then select 'Custom Queries' --> 'Edit Custom Queries' and then have it call your procedure as:
exec view_create<ObjectList>
Then you can right click on the table name and in one click create the view as Toad will pass the name of the table into the procedure.
Also in the procedure you may want to recompile the schema, so after the view is created do:
sys.utl_recomp.recomp_parallel(4, 'XYZ');
If you develop a script of some sort which can semi automate, it makes things easy.
Hope this helps...

Create a Synonym for a database / Change DB views point to

I know databases aren't supported by CREATE SYNONYM, but I'm looking to achieve the functionality this would provide.
We've got Database A which contains views to tables on Database B. The trouble is "Database B" isn't always called "Database B". We use database projects for deployments, which at the moment fall over with an "Invalid Object Name" error if there isn't a "Database B".
The workaround at the moment is to open up the .dbschema file and do a find and replace. I guess another option would be to create a load of table synonyms.
What's the best way of changing the database a number of views reference without changing each view individually?
Thanks
Synonyms are a good way to do this. You have to create the synonyms at the object level though (as you've discovered). An easy way to do this would be to write a script that runs through the list of tables in DatabaseB (from your example) and creates a synonym for each one in DatabaseA. Keep the name of the synonym the same so the code in your views doesn't have to change. For instance, you you have tbl_a, tbl_b, and tbl_c in DatabaseB, you'd want your script to eventually do the following:
create synonym [otherDb].[tbl_a] for [DatabaseB].[schemaB].[tbl_a]
create synonym [otherDb].[tbl_b] for [DatabaseB].[schemaB].[tbl_b]
create synonym [otherDb].[tbl_c] for [DatabaseB].[schemaB].[tbl_c]
Now, in your view code, you'll always use [otherDb].[tbl_a], [otherDb].[tbl_b], and [otherDb].[tbl_c]. Hope this makes sense.
Last year I helped my current client with the implementation of a very similar design. We wrote a set of functions and stored procedures which generate the views automatically. Whenever you need to change the target database it generates the code to drop and recreate all of the views.
The code wasn't too difficult. It just uses the system tables to generate view code. I also wrote a Powershell prototype that uses SMO to do the same thing. The key is to have it automated to the point of requiring a single call so that you can do it easily and accurately.
We also included an exception table that used a pattern match of tables to exclude from view generation. It included a schema column and a table name column, each of which accepted LIKE patterns, so you could put "my_schema" and "%" to exclude all tables in the my_schema schema.
One master stored procedure accepted a target database name and would generate the entire script. Once the script is generated you can run it in SSMS or have that part automated as well.
This whole thing would be even easier if you just wanted to generate synonyms. We were using views so that we could change column lists, etc. and have the view DB look different than the target DB where needed.