Oracle: Query identical table in multiple schema in single line - sql

In Oracle, is there a way to query the same, structurally identical table out of multiple schema within the same database in single line? Obviously assuming the user has permissions to access all schema, I could build a query like:
select * from schema1.SomeTable
union all
select * from schema2.SomeTable
But is it possible, given the right permissions to say something like:
select * from allSchema.SomeTable
...and bring back all rows for all the schema? And related to this, is it possible to pick which schema, such as:
select * from allSchema.SomeTable where schemaName in ('schema1','schema2')

The simplest option, as far as I can tell, is to create a VIEW (as UNION of all tables across all those users), and then SELECT FROM VIEW.
For example:
create or replace view my_view as
select 'schema_1' source_schema, id, name from schema_1.table union
select 'schema_2' source_schema, id, name from schema_2.table union
...
-- select all
select * from my_view;
-- select all that belongs to one of schemas
select * from my_view where source_schema = 'schema_1';

Related

Creating a list in SQL and iterating through the list after the FROM line

I want to access some table like Toyota_Corolla, Toyota_Camry, Toyota_Prius, Toyota_Rav4
Instead of typing out multiple SELECT statements like the following:
SELECT * FROM Toyota_Corolla;
SELECT * FROM Toyota_Camry;
SELECT * FROM Toyota_Prius;
SELECT * FROM Toyota_Rav4;
Is there a way to create a list of strings like ['Corolla', 'Camry', 'Prius', Rav4'] and iterate through the list after the FROM line to something similar to:
SELECT * FROM 'Toyota_'` + 'some loop to iterate the list of car model'
I know for my example, it's easier to just type out the whole thing, but what about the situation when Toyota has hundred of models?
This is MS SQL Server DBMS
No. First, you should fix your data model so you have a single table with an additional column for the Toyota model. That is the right way to store the data.
With the data you have, you can emulate this with a view:
create view vw_toyota as
select 'Corolla' as toyota_model, t.* from Toyota_Corolla t union all
select 'Camry' as toyota_model, t.* from Toyota_Camry t union all
select 'Prius' as toyota_model, t.* from Toyota_Prius t union all
select 'Rav4' as toyota_model, t.* from Toyota_Rav4 t;
This also adds the source table information.
And then do:
select *
from vw_toyota;

Regex put name schema for 'table' in select query syntax

How can I put with regex, schema name table, for query select?
Query doesn't have fixed size.
Example:
select * from t1 union select * from t2
Result:
select * from schema1.t1 union select * from schema1.t2
Thanks!
(1) If you are using it in a code, maybe you can do a search and replace at front end as Luk suggested.
(2) Alternatively, in your current session you can set default schema as schema1 so your query would work without schema name. But it would depend on your database name.
Like in Oracle you can do
ALTER SESSION SET CURRENT_SCHEMA=schema1
Now select * from t1 would effectively mean select * from schema1.t1.
You can search how to set default schema in <your database> in google and you would get syntax for other databases as well.

SQL Server : compare two tables with UNION and Select * plus additional label column

I've been playing around with the sample on Jeff' Server blog to compare two tables to find the differences.
In my case the tables are a backup and the current data. I can get what I want with this SQL statement (simplified by removing most of the columns). I can then see the rows from each table that don't have an exact match and I can see from which table they come.
SELECT
MIN(TableName) as TableName
,[strCustomer]
,[strAddress1]
,[strCity]
,[strPostalCode]
FROM
(SELECT
'Old' as TableName
,[JAS001].[dbo].[AR_CustomerAddresses].[strCustomer]
,[JAS001].[dbo].[AR_CustomerAddresses].[strAddress1]
,[JAS001].[dbo].[AR_CustomerAddresses].[strCity]
,[JAS001].[dbo].[AR_CustomerAddresses].[strPostalCode]
FROM
[JAS001].[dbo].[AR_CustomerAddresses]
UNION ALL
SELECT
'New' as TableName
,[JAS001new].[dbo].[AR_CustomerAddresses].[strCustomer]
,[JAS001new].[dbo].[AR_CustomerAddresses].[strAddress1]
,[JAS001new].[dbo].[AR_CustomerAddresses].[strCity]
,[JAS001new].[dbo].[AR_CustomerAddresses].[strPostalCode]
FROM
[JAS001new].[dbo].[AR_CustomerAddresses]) tmp
GROUP BY
[strCustomer]
,[strAddress1]
,[strCity]
,[strPostalCode]
HAVING
COUNT(*) = 1
This Stack Overflow Answer gives me a much cleaner SQL query but does not tell me from which table the rows come.
SELECT * FROM [JAS001new].[dbo].[AR_CustomerAddresses]
UNION
SELECT * FROM [JAS001].[dbo].[AR_CustomerAddresses]
EXCEPT
SELECT * FROM [JAS001new].[dbo].[AR_CustomerAddresses]
INTERSECT
SELECT * FROM [JAS001].[dbo].[AR_CustomerAddresses]
I could use the first version but I have many tables that I need to compare and I think that there has to be an easy way to add the source table column to the second query. I've tried several things and googled to no avail. I suspect that maybe I'm just not searching for the correct thing since I'm sure it's been answered before.
Maybe I'm going down the wrong trail and there is a better way to compare the databases?
Could you use the following setup to accomplish your goal?
SELECT 'New not in Old' Descriptor, *
FROM
(
SELECT * FROM [JAS001new].[dbo].[AR_CustomerAddresses]
EXCEPT
SELECT * FROM [JAS001].[dbo].[AR_CustomerAddresses]
) a
UNION
SELECT 'Old not in New' Descriptor, *
FROM
(
SELECT * FROM [JAS001].[dbo].[AR_CustomerAddresses]
EXCEPT
SELECT * FROM [JAS001new].[dbo].[AR_CustomerAddresses]
) b
You can't add the table name there because union, except, and intersection all compare all columns. This means you can't differentiate between them by adding the table name to the query. A group by gives you control over what columns are considered in finding duplicates so you can exclude the table name.
To help you with the large number of tables you need to compare you could write a sql query off the metadata tables that hold table names and columns and generate the sql commands dynamically off those values.
Derive one column using table names like below
SELECT MIN(TableName) as TableName
,[strCustomer]
,[strAddress1]
,[strCity]
,[strPostalCode]
,table_name_came
FROM
(SELECT 'Old' as TableName
,[JAS001].[dbo].[AR_CustomerAddresses].[strCustomer]
,[JAS001].[dbo].[AR_CustomerAddresses].[strAddress1]
,[JAS001].[dbo].[AR_CustomerAddresses].[strCity]
,[JAS001].[dbo].[AR_CustomerAddresses].[strPostalCode]
,'[JAS001].[dbo].[AR_CustomerAddresses]' as table_name_came
FROM [JAS001].[dbo].[AR_CustomerAddresses]
UNION ALL
SELECT 'New' as TableName
,[JAS001new].[dbo].[AR_CustomerAddresses].[strCustomer]
,[JAS001new].[dbo].[AR_CustomerAddresses].[strAddress1]
,[JAS001new].[dbo].[AR_CustomerAddresses].[strCity]
,[JAS001new].[dbo].[AR_CustomerAddresses].[strPostalCode]
,'[JAS001new].[dbo].[AR_CustomerAddresses]' as table_name_came
FROM [JAS001new].[dbo].[AR_CustomerAddresses]
) tmp
GROUP BY [strCustomer]
,[strAddress1]
,[strCity]
,[strPostalCode]
,table_name_came
HAVING COUNT(*) = 1

SQL Server Select from multiple tables in array

Simple question about SQL Server 2808.
View1:
Select name from sys.tables where name like 'ab%'
Result:
Name
----
ab01
ab02
abxyz etc...
Now I want to query over those tables.
Select * from view1
Of course I get ab01, ab02, abxyz. What I want is to query over the content
select * from ab01, ab02, abxyz
best of all would by to use union over the view1 query
Something like
Union view1
would be something like
Select * from ab01
union
select * from ab02
....
any ideas?
Greets
Use a cursor.
Create a temporary table.
Loop through the cursor and add the results to the temporary table.
Select all from temporary table.

Oracle SQL - select from view more rows than running select in the view

When I run this SQL, I get 116,463 rows.
select * from appsdisc.appsdisc_phones_gen_v
When I run the select that is in the view definition script, I get 11,702 rows.
I can't figure out why the result set is different.
The view script is as follows.
CREATE OR REPLACE FORCE VIEW APPSDISC.APPSDISC_PHONES_GEN_V
(PARTY_ID, CUSTOMER_ID, CUSTOMER_NUMBER, PHONE_NUMBER, PHONE_TYPE)
AS
SELECT party_id,
customer_id,
customer_number,
phone_number,
phone_type
FROM appsdisc_phones_v pv1
WHERE pv1.phone_type LIKE
DECODE (TRIM (SUBSTR (pv1.attribute14, 1, 4)),
'FR', 'FR T%',
'PHONE')
AND pv1.contact_point_id =
(SELECT MIN (pv2.contact_point_id)
FROM appsdisc_phones_v pv2
WHERE pv2.customer_id = pv1.customer_id
AND pv2.phone_type LIKE
DECODE (
TRIM (SUBSTR (pv1.attribute14, 1, 4)),
'FR', 'FR T%',
'PHONE'));
If you're running the view query exactly as it is, and you are not logged in as APPSDISC, you might be querying your own table (or view), since appsdisc_phones_v isn't prefixed by the schema in the view script. Hopefully this is a development environment and you have an old copy for a valid reason.
Here's a demo of the effect I think you're seeing. As one user (SOUSER1) I can create and populate a table with a view on top of it, and grant access to that view to a different user. Notice I don't need to grant access to the underlying table directly.
create table my_table (id number);
insert into my_table
select level as id from dual connect by level <= 1000;
commit;
create view souser1.my_view as select * from my_table;
grant select on souser1.my_view to souser2;
select count(*) from my_view;
COUNT(*)
----------
1000
select count(*) from my_table;
COUNT(*)
----------
1000
I didn't specify the schema in the select inside the view statement, so it's going to be the same as the view owner, which is SOUSER1 in this case.
Then as a second user (SOUSER2) I can create my own version of the table, with fewer rows. Querying the view still shows the row count from the SOUSER1 table, not my own.
create table my_table (id number);
insert into my_table
select level as id from dual connect by level <= 100;
commit;
select count(*) from souser1.my_view;
COUNT(*)
----------
1000
If I run the query from the original view I'm seeing my own copy of the table, which is smaller, because the table name isn't qualified with the schema name - hence it defaults to my own:
select count(*) from my_table;
COUNT(*)
----------
100
So seeing a different number of rows makes sense as long as there are two versions of the table and you haven't specified which you want to query.
And in my case, if I try to query the other schema's table directly I get an error, since I didn't grant any privileges on that:
select count(*) from souser1.my_table;
SQL Error: ORA-00942: table or view does not exist
00942. 00000 - "table or view does not exist"
But you'd see the same error querying my_table if you don't have your own copy, you don't set your current schema on login, and you don't have a synonym pointing to a table in some schema.
Gordon is right, the select should return the same results as the view. Issues such as running the query in different schema, databases, or over database links could explain what you are observing. You can see this by running the two SQL commands in the same database and schema below and comparing the values returned by both.
First, confirm the number of rows the view returns with the SQL:
SELECT COUNT(*) FROM APPSDISC.APPSDISC_PHONES_GEN_V;
Then confirm the number of rows the query for the view returns with the SQL:
WITH RESULTS AS (
SELECT party_id,
customer_id,
customer_number,
phone_number,
phone_type
FROM appsdisc_phones_v pv1
WHERE pv1.phone_type LIKE
DECODE (TRIM (SUBSTR (pv1.attribute14, 1, 4)),
'FR', 'FR T%',
'PHONE')
AND pv1.contact_point_id =
(SELECT MIN (pv2.contact_point_id)
FROM appsdisc_phones_v pv2
WHERE pv2.customer_id = pv1.customer_id
AND pv2.phone_type LIKE
DECODE (
TRIM (SUBSTR (pv1.attribute14, 1, 4)),
'FR', 'FR T%',
'PHONE')))
SELECT COUNT(*)
FROM RESULTS
/
Both queries should be returning the same values. If not then there is more to this issue than a query returning a different number of rows.