SQL Server 2005 Express - generate script to create VIEW based on relational tables? - view

Is there a way in SQL Server 2005 Express to generate a script that would create a VIEW based on tables primary/foreign key relationships?
I have multiple databases with thousands of tables, and its very time consuming to look at the "table dependencies" and try to JOIN data in the query window.
Thanks

This Query return Create statement for tables, but you must first note that:
1. only works for 1 column foreign key references
2. has not been tested for sql server express 2005, but works fine for Sql server 2005
create function dbo.func59C217D64BC54EA0B841BF1AB43D9398(#table1 nvarchar(1000), #table2 nvarchar(1000))
returns nvarchar(max)
as
begin
declare #sql nvarchar(max)
set #sql = ''
select #sql = #sql + dr + '.[' +cc +'] AS ['+ cc+ ISNULL(rr,'') + '],'
from (
select column_name cc,
dr = case when table_schema + '.' +table_name = #table1 then 'a' else 'b' end,
cast(NULLIF(row_number() over (partition by column_name order by table_name),1) as nvarchar) rr
from INFORMATION_SCHEMA.COLUMNS where table_schema + '.' +table_name in
(#table1,#table2)
) i
return substring(#sql,1,len(#sql) - 1)
end
GO
select cast(
'CREATE VIEW ['+r.CONSTRAINT_SCHEMA+'].[vw' +cp.TABLE_NAME+cf.TABLE_NAME+ ']
AS SELECT '+dbo.func59C217D64BC54EA0B841BF1AB43D9398(cp.TABLE_SCHEMA+'.' +cp.TABLE_NAME,cf.TABLE_SCHEMA+ '.' +cf.TABLE_NAME)+' FROM ['+cp.TABLE_SCHEMA+'].['+cp.TABLE_NAME+'] AS a
JOIN ['+cf.TABLE_SCHEMA+'].['+cf.TABLE_NAME +'] AS b
ON a.['+cp.COLUMN_NAME+'] = b.['+cf.COLUMN_NAME +']' as ntext) as sql
from INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS r
JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE cf ON r.CONSTRAINT_NAME = cf.CONSTRAINT_NAME
JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE cp ON r.UNIQUE_CONSTRAINT_NAME = cP.CONSTRAINT_NAME
GO
DROP function dbo.func59C217D64BC54EA0B841BF1AB43D9398
hope I helped, or at least make you started

Related

Oracle EF Database first is not completing

When I attempt to reverse engineer models off of an Oracle database, I am getting errors when the table in question has more than one trigger on the a column. I am putting a web UI on an upgraded Oracle 7 database (it has been migrated to Oracle 18C). The original system is an old Unix terminal UI. My solution is read only. Solution is .NET Core 3.1 and Oracle.EntityFrameworkCOre is 3.19.110.
When I run the above command on a table that has more than one trigger on a column, it errors.
Scaffold-DbContext "User Id=<user>; Password=<pwd>; Data Source=<datasource>;" Oracle.EntityFrameworkCore -OutputDir Models -Context GlobalContext
Using verbose mode I get the following.
Sequence contains more than one matching element
at System.Linq.ThrowHelper.ThrowMoreThanOneMatchException()
The generated SQL is
select u.*, v.trigger_name, v.table_name, v.column_name, v.table_owner
from (SELECT sys_context('userenv', 'current_schema') as schema, c.table_name, c.column_name, c.column_id, c.data_type, c.char_length, c.data_length, c.data_precision, c.data_scale, c.nullable, c.identity_column, c.data_default, c.virtual_column, c.hidden_column
FROM user_tab_cols c INNER JOIN (select distinct object_name as table_name from user_objects where object_type in ('TABLE', 'VIEW', 'MATERIALIZED VIEW')) t ON t.table_name=c.table_name WHERE t.table_name <> '__EFMigrationsHistory' AND (t.table_name IN (:t0) AND CONCAT(sys_context('userenv', 'current_schema'), CONCAT('.', t.table_name)) IN (:sdott0)) )u
left join USER_TRIGGER_COLS v on u.table_name = v.table_name and u.column_name = v.column_name and u.schema = v.table_owner
ORDER BY u.column_id
The results are as follows (I've made the table/triggers generic, but you see the issue)
Short of dropping the triggers, is there a way to reverse engineer the table?

How to use SQL query to define table in dbtable?

In JDBC To Other Databases I found the following explanation of dbtable parameter:
The JDBC table that should be read. Note that anything that is valid in a FROM clause of a SQL query can be used. For example, instead of a full table you could also use a subquery in parentheses.
When I use the code:
CREATE TEMPORARY TABLE jdbcTable
USING org.apache.spark.sql.jdbc
OPTIONS (
url "jdbc:postgresql:dbserver",
dbtable "mytable"
)
everything works great, but the following:
dbtable "SELECT * FROM mytable"
leads to the error:
What is wrong?
Since dbtable is used as a source for the SELECT statement it has be in a form which would be valid for normal SQL query. If you want to use subquery you should pass a query in parentheses and provide an alias:
CREATE TEMPORARY TABLE jdbcTable
USING org.apache.spark.sql.jdbc
OPTIONS (
url "jdbc:postgresql:dbserver",
dbtable "(SELECT * FROM mytable) tmp"
);
It will be passed to the database as:
SELECT * FROM (SELECT * FROM mytable) tmp WHERE 1=0
Code In Scala
val checkQuery = "(SELECT * FROM " + inputTableName + " ORDER BY " + columnName + " DESC LIMIT 1) AS timetable"
val timeStampDf = spark.read.format("jdbc").option("url", url).option("dbtable", checkQuery).load()
Adding an alias is also necessary after the query in parenthesis.

oracle with clause error in adodb

I am not able to use the with clause in oracle adodb connection. I have tried both wrapping the qry is a select * from (myquery) and adding a , before my with clause. All create errors.
Here is the query
`WITH TEMPa AS (select _nbr, sum(ending) as Cost from t1 group by _nbr),
TEMPB AS (select _nbr, cost,entity
from t2
where end_tms is null and sale_date is null and entity = 110)
SELECT
TEMPA._nbr
,TEMPA.cost
,TEMPb._nbr
,TEMPB._cost
,tempb.entity
,(tempb._cost - tempa.cost) as Difference
FROM TEMPA, TEMPB
WHERE TEMPA._nbr = TEMPB._nbr(+)
and tempa.cost <> tempb.cost`
Any help would be awesome!

Finding sequences and triggers associated with an Oracle table

I have used this query to fetch the list of sequences belonging to an Oracle database user:
SELECT * FROM all_sequences x,all_tables B
WHERE x.sequence_owner=B.owner AND B.TABLE_NAME='my_table';
But that database user is having many more sequence also, so the query returns me all the sequence of the database user. Can anybody help me to find the particular sequence of my_table using query so that I can get the auto increment id in my application.
i want the query which fetch list of table of my database user with the sequence and triggers used in the table
You can get the triggers associated with your tables from the user_triggers view. You can then look for any dependencies recorded for those triggers in user_dependencies, which may include objects other than sequences (packages etc.), so joining those dependencies to the user_sequences view will only show you the ones you are interested in.
Something like this, assuming you are looking at your own schema, and you're only interesting in triggers that references sequences (which aren't necessarily doing 'auto increment', but are likely to be):
select tabs.table_name,
trigs.trigger_name,
seqs.sequence_name
from user_tables tabs
join user_triggers trigs
on trigs.table_name = tabs.table_name
join user_dependencies deps
on deps.name = trigs.trigger_name
join user_sequences seqs
on seqs.sequence_name = deps.referenced_name;
SQL Fiddle demo.
If you're actually looking at a different schema then you'll need to use all_tables etc. and filter and join on the owner column for the user you're looking for. And if you want to include tables which don't have triggers, or triggers which don't refer to sequences, you can use outer joins.
Version looking for a different schema, though this assumes you have the privs necessary to access the data dictionary information - that the tables etc. are visible to you, which they may not be:
select tabs.table_name,
trigs.trigger_name,
seqs.sequence_name
from all_tables tabs
join all_triggers trigs
on trigs.table_owner = tabs.owner
and trigs.table_name = tabs.table_name
join all_dependencies deps
on deps.owner = trigs.owner
and deps.name = trigs.trigger_name
join all_sequences seqs
on seqs.sequence_owner = deps.referenced_owner
and seqs.sequence_name = deps.referenced_name
where tabs.owner = '<owner>';
If that can't see them then you might need to look at the DBA views, again if you have sufficient privs:
select tabs.table_name,
trigs.trigger_name,
seqs.sequence_name
from dba_tables tabs
join dba_triggers trigs
on trigs.table_owner = tabs.owner
and trigs.table_name = tabs.table_name
join dba_dependencies deps
on deps.owner = trigs.owner
and deps.name = trigs.trigger_name
join dba_sequences seqs
on seqs.sequence_owner = deps.referenced_owner
and seqs.sequence_name = deps.referenced_name
where tabs.owner = '<owner>';
One way would be to run these queries to check if there are any sequence's Pseudocolumns (NEXTVAL and CURRVAL ) used in your functions , procedures, packages, Triggers or PL/SQL JAVA SOURCE.
select * from user_source where
UPPER(TEXT) LIKE '%NEXTVAL%';
select * from all_source where
UPPER(TEXT) LIKE '%NEXTVAL%';
Then go to the specific Procedure, Function or Trigger to check which column/table gets populated by a sequence.
The query could also be used with '%CURRVAL%'
This might not help if you are running inserts from JDBC or other external applications using a sequence.
Oracle 12c introduced the IDENTITY columns, using which you could create a table with an identity column, which is generated by default.
CREATE TABLE t1 (c1 NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY,
c2 VARCHAR2(10));
This will internally create a sequence that auto-generates the value for the table's column.So, If you would like to know which sequence generates the value for which table, you may query the all_tab_columns
SELECT data_default AS sequence_val
,table_name
,column_name
FROM all_tab_columns
WHERE OWNER = 'HR'
AND identity_column = 'YES';
SEQUENCE_VAL |TABLE_NAME |COLUMN_NAME
-----------------------------------------|-------------------------------------
"HR"."ISEQ$$_78160".nextval |T1 |C1
I found a solution to this problem to guess the sequence of a particular sequence
select * from SYS.ALL_SEQUENCES where SEQUENCE_OWNER='OWNER_NAME' and LAST_NUMBER between (select max(FIELD_NAME) from TABLE_NAME) and (select max(FIELD_NAME)+40 from TABLE_NAME);
This query will guess by search the LAST_NUMBER of the sequence value between MAX value of the field using sequence and Max value + 40 (in my case cache value is 20, so I put 40)
select SEQUENCE_NAME from sys.ALL_TAB_IDENTITY_COLS where owner = 'SCHEMA_NAME' and table_name = 'TABLE_NAME';

Return Oracle column names in table.column format?

Is there any setting or method I can use to get Oracle to return results in <table>.<column> format? For example:
Query:
SELECT *
FROM foo f
INNER JOIN bar b
ON b.foo_id = f.id
Desired results:
F.ID F.BLAH B.ID B.FOO_ID B.BLAH
--------------------------------------------------------
1 blah 7 1 blah
2 blah 8 2 blah
3 blah 9 2 blah
The obvious solution is to individually alias each column SELECT f.id AS F_ID, ...; however, I'm needing to export some very large legacy tables (300+ columns), so using this method would cause the queries to be enormous and impractical.
There is no "option" in Oracle to do this; you may be able to find a client that allows you to do so as this is a job that would normally be done in the client; I don't know of one.
To expand upon tbone's answer you're going to have to do this dynamically. This does not mean that you have to list every column. You would use the data dictionary, specifically all_tab_columns or user_tab_columns to create your query. It would be easier to create a view with the exact definition you want so that you can re-use it if you want.
The aim is to use the fact that the columns existence is stored in a table as a string in order to create a query to use that column. As the column names and table names are stored as strings you can use string aggregation techniques to easily create a query or DDL statement that you can then manually, or dynamically, execute.
If you're using Oracle 11g Release 2 the listagg function is available to help you:
select 'create or replace view my_view as
select '
|| listagg( table_name || '.' || column_name
|| ' as '
|| substr(table_name,1,1) || '_'
|| column_name, ', ')
within group
( order by case when table_name = 'FOO' then 0 else 1 end
, column_id
)
|| ' from foo f
join bar b
on f.id = b.foo_id'
from user_tab_columns
where table_name in ('FOO','BAR')
;
Assuming this table structure:
create table foo ( id number, a number, b number, c number);
create table bar ( foo_id number, a number, b number, c number);
This single query produces the following:
create or replace view my_view as
select FOO.ID as F_ID, FOO.A as F_A, FOO.B as F_B, FOO.C as F_C
, BAR.FOO_ID as B_FOO_ID, BAR.A as B_A, BAR.B as B_B, BAR.C as B_C
from foo f
join bar b on f.id = b.foo_id
and here's a SQL Fiddle to prove it.
In you're not using 11.2 you can achieve exactly the same results using the undocumented function wm_concat or the user-defined function stragg, which was created by Tom Kyte. Oracle Base has an article on string aggregation techniques and there are many posts on Stack Overflow.
As a little addendum you can actually create exactly what you're looking for with a small change to the above query. You can use a quoted identifier to create a column in the TABLE_NAME.COLUMN_NAME format. You have to quote it as . is not a valid character for an object name in Oracle. The benefit of this is that you gain exactly what you want. The downside is that querying the created view is a huge pain if you don't use select * from ...; selecting named columns will require them to be quoted.
select 'create or replace view my_view as
select '
|| listagg( table_name || '.' || column_name
|| ' as '
|| '"' || table_name || '.'
|| column_name || '"', ', ')
within group
( order by case when table_name = 'FOO' then 0 else 1 end
, column_id
)
|| ' from foo f
join bar b
on f.id = b.foo_id'
from user_tab_columns
where table_name in ('FOO','BAR')
;
This query returns:
create or replace view my_view as
select FOO.ID as "FOO.ID", FOO.A as "FOO.A", FOO.B as "FOO.B", FOO.C as "FOO.C"
, BAR.FOO_ID as "BAR.FOO_ID", BAR.A as "BAR.A"
, BAR.B as "BAR.B", BAR.C as "BAR.C"
from foo f
join bar b on f.id = b.foo_id
Using aliases wouldn't make the queries become impractical, its just not nearly as convenient as typing *. Use dynamic SQL to generate the columns for you:
select 'f.' || column_name || ' as F_' || column_name || ','
from all_tab_columns
where table_name = 'FOO'
order by column_id;
Do the same for any other wide tables you need, and copy/paste into your query. Also note the 30 char limit, hopefully none of your columns are over 28 in size.

Resources