Propagate Indexes when CREATE TABLE from two tables in PostgreSQL - database

I create a table by linking two different tables in PostgreSQL. I do this with a sentence like this:
CREATE TABLE t_aux_prop_delay
AS
SELECT r.cell, r.kpi_name, r.the_geom, d.max as pd_end_point, round(k.avg_samples, 2) AS avg_samples
from t_cell_regions r, kpi_definition d,
(
SELECT cell, kpi_name, avg(kpi_value) AS avg_samples
from t_prop_delay_values
GROUP BY cell, kpi_name
) k
WHERE r.kpi_name = d.kpi_name
AND r.cell = k.cell
AND r.kpi_name = k.kpi_name
ORDER BY r.cell, d.max;
I want to know if it is possible to propagate the indexes from one of those tables to the new table so I do not have to create them all over again.

Maybe this select can help you:
SELECT REPLACE(indexdef, indexname, indexname||1)
FROM pg_indexes
WHERE TABLENAME = 'YOUR_TABLE_NAME';
It will give you a "CREATE INDEX" code with a different name (that is why I have added/concatenated 1 at the end). You are creating a new object so it has to have a different name...
And here is another code where you can also get the "CREATE INDEX" code with the different table name.
SELECT REPLACE(REPLACE(indexdef, indexname, indexname||1), tablename, 'your_tablename')
FROM pg_indexes
WHERE TABLENAME = 'personeel_medspec';

Related

Copy tables selected from sys.tables to new DB

Note:- I have a Database(DB) with Thousands of Tables.
I want to Copy all Tables with Name like 'TableType1%' to a new Database(DB).
I can easily get a list of the tables:
select * from sys.tables t
where schema_name(t.schema_id) = 'S1' AND [name] LIKE 'TableType1%'
But how do I copy them to a new Database(DB)?
I CANNOT do this manually, as there are too many Tables.
I would like to use
INSERT INTO....
Type statement, but don't know how to put it into Select Statement above.
Select * into DestinationDB from SourceDB.sys.tables where name like 'TableType1%'
Note:- In database (DestinationDB) the physical tables are created with same name in source databse (SourceDB)

Generate an sql query from multiple tables, then create new table

I have a tricky bit of sql query I need to write. To best explain it, I will post some pictures to show three tables. The first two are tables which already contain data, the last table will be the table I need created using data from the first two:
You can use JOIN for each column you want to get in final table:
SELECT
Width.itemNumber,
Width.itemValue as 'Width',
Height.itemValue as 'Height',
[Type].valueID as 'Type',
Frame.valueID as 'Frame',
Position.valueID as 'Position'
INTO third_table_name
FROM itemMaster_itemValue Width
JOIN itemMaster_itemValue Height ON Width.itemNumber=Height.itemNumber AND Height.itemPropertyID='Height'
JOIN itemMaster_EnumValue 'Type' ON Width.itemNumber=[Type].itemNumber AND [Type].itemPropertyID='Type'
JOIN itemMaster_EnumValue Frame ON Width.itemNumber=Frame.itemNumber AND Frame.itemPropertyID='Frame'
JOIN itemMaster_EnumValue Position ON Width.itemNumber=Position.itemNumber AND Position.itemPropertyID='Position'
WHERE Width.itemPropertyID='Width'
I'm not sure if you actually are wanting to create a table for the third view or just a query (in access) / view (in MS SQL Server). Here is how I would do it:
In MS-Access:
Step 1 (Which can end here if all you need is a way to see the data in this format)
TRANSFORM Max(P.vid) AS MaxOfvid
SELECT P.inum
FROM (SELECT itemNumber as inum, itemPropertyID as ival, itemValue as vid
FROM itemMaster_itemValue
UNION
SELECT Enum.itemNumber AS inum, Enum.itemPropertyID AS ival, Enum.valueID AS vid
FROM itemMaster_EnumValue AS Enum) AS P
GROUP BY P.inum
PIVOT P.ival;
Step 2 (If you need to actually create an additional table)
Select * INTO tableName FROM previousPivotQueryName;
That will get you what you need in Access.
The SQL Server part is a little different and can all be done in one T-SQL Statement dbo.test is the name of the table you will create... If you are creating a table for performance reasons then this statement can be put into a job and run nightly to create the table. The Drop Table line will have to be removed before the first time you run it or it will fail because the table will not exist yet:
Drop Table dbo.Test
Select * INTO dbo.Test FROM (
/*just use the following part if you only need a view*/
SELECT *
FROM (SELECT itemNumber as inum, itemPropertyID as ival, itemValue as vid
FROM dbo.itemMaster_itemValue
UNION
SELECT Enum.itemNumber AS inum, Enum.itemPropertyID AS ival, Enum.valueID AS vid
FROM dbo.itemMaster_EnumValue AS Enum) P
PIVOT (max(vid) FOR ival IN([Width],[Height],[Type],[Frame],[Position])) PV)PVT;
And that should get you what you need in the most efficient way possible without using a bunch of joins. :)

how to update table(new_DB) from old table(old_DB)

What I have:
1 table(table is in both DB's)
2 databases(currently used + archived from last year(old))
"ID" is the primary key for the table.
my issue:
archived database table has rows in it that is not present in the currently used database table. Can anyone tell me how I go about updating the currently used database table from the old database table(i.e. insert * unique rows from old database table into new database table)
It sounds simple enough but wanted some advice before proceeding as I DO NOT want duplicate rows, I just want to throw the rows in the old table(that IS NOT present in the currently used database table) into the new one(copy only is fine).
I hope I explained clearly enough.
Insert rows from the new table only if row with same id not exists in old table:
insert into old_table select * from new_table nt
where not exists (select 1 from old_table
where id = nt.id)
(Specifying columns, both inserted and selected, is nice - but I'm lazy here...)
You can usually address tables from other databases by prefixing the database name: new_db.foo_table or old_db.foo_table. This way you can look for rows in the old table that have no duplicates in the new table:
select *
from old_db.foo_table as old_foo
where not exists (
select 1
from new_db.foo_table as new_foo
where new_foo.key_field = old_foo.key_field
-- add more comparisons as needed
);
Then you can use the insert into new_db.foo_table select ... syntax to put the records into the new table.
Use LEFT JOIN filtering NULLs in target table. I think it will be faster
INSERT INTO NEW_TABLE
SELECT ot.* FROM OLD_TABLE ot
LEFT JOIN NEW_TABLE nt on ot.ID = nt.ID
WHERE nt.ID IS NULL

Copy missing rows from one table to another with multi-column primary key

This topic is related to Copy missing rows from one table to another in sql server with stored procedure but this time the problem is a bit more complex.
I have to tables in different databases (on the same server) that are identical. I need to transfer the data rows from the left database table to the right database table, but I only want to transfer the rows that aren't in the right database table already.
My table have four primary keys, see image
I'd like to use something like this
insert into [EXTERN_EPI6R2].[dbo].[tblBigTableReference]
select * from [EXTERN].[dbo].[tblBigTableReference]
where (
pkId not in (select pkId
from [EXTERN_EPI6R2].[dbo].[tblBigTableReference])
and PropertyName not in (select PropertyName
from [EXTERN_EPI6R2].[dbo].[tblBigTableReference])
and IsKey not in (select IsKey
from [EXTERN_EPI6R2].[dbo].[tblBigTableReference])
and [Index] not in (select [Index]
from [EXTERN_EPI6R2].[dbo].[tblBigTableReference])
)
But, that wont work since the stacking of the conditions is wrong in some way.
Im using SQL Server 2008 R2
Your query is not correct because your various conditions can be matched on different rows.
insert into [EXTERN_EPI6R2].[dbo].[tblBigTableReference]
select * from [EXTERN].[dbo].[tblBigTableReference] AS s
where NOT EXISTS
(
SELECT 1 FROM [EXTERN_EPI6R2].[dbo].[tblBigTableReference] AS d
WHERE d.pkId = s.pkId
AND d.PropertyName = s.PropertyName
AND d.IsKey = s.IsKey
AND d.[Index] = s.[Index] -- terrible column name
);
But this begs the question - why are all four of these columns part of the key? Is pkId not enough? If it isn't, it sure has a strange and incorrect name.

How to SELECT * but without "Column names must be unique in each view"

I need to encapsulate a set of tables JOINs that we freqently make use of on a vendor's database server. We reuse the same JOIN logic in many places in extracts etc. and it seemed a VIEW would allow the JOINs to be defined and maintained in one place.
CREATE VIEW MasterView
AS
SELECT *
FROM entity_1 e1
INNER JOIN entity_2 e2 ON e2.parent_id = entity_1.id
INNER JOIN entity_3 e3 ON e3.parent_id = entity_2.id
/* other joins including business logic */
etc.
The trouble is that the vendor makes regular changes to the DB (column additions, name changes) and I want that to be reflected in the "MasterView" automatically.
SELECT * would allow this, but the underlying tables all have ID columns so I get the "Column names in each view must be unique" error.
I specifically want to avoid listing the column names from the tables because a) it requires frequent maintenance b) there are several hundred columns per table.
Is there any way to achieve the dynamism of SELECT * but effectively exclude certain columns (i.e. the ID ones)
Thanks
I specifically want to avoid listing the column names from the tables because a) it requires frequent maintenance b) there are several hundred columns per table.
In this case, you can't avoid it. You must specify column names and for those columns with duplicate names use an alias. Code generation can help with these many columns.
SELECT * is bad practice regardless - if someone adds a 2GB binary column to one of these tables and populates it, do you really want it to be returned?
One simple method to generate the columns you want is
select column_name+',' from information_schema.columns
where table_name='tt'
and column_name not in('ID')
As well as Oded's answer (100% agree with)...
If someone changes the underlying tables, you need view maintenance anyway (with sp_refreshview). The column changes will not appear in the view automatically. See "select * from table" vs "select colA, colB, etc. from table" interesting behaviour in SQL Server 2005
So your "reflected in the "MasterView" automatically requirement can't be satisfied anyway
If you want to ensure the view is up to date, use WITH SCHEMABINDING which will prevent changes to the underlying tables (until removed or dropped). Then make column changes, then re-apply the view
I had the same issue, see example below:
ALTER VIEW Summary AS
SELECT * FROM Table1 AS t1
INNER JOIN Table2 AS t2 ON t1.Id = t2.Id
and I encountered that error you mentioned, the easiest solution is using the alias before * like this:
SELECT t1.* FROM Table1 AS t1
INNER JOIN Table2 AS t2 ON t1.Id = t2.Id
You shouldn't see that error anymore.
I had gone with this in the end, building off of Madhivanan's suggestion. It's similar to what t-clausen.dk later suggested (thanks for your efforts) though I find the xml path style more elegant than cursors / rank partitions.
The following recreates the MasterView definition when run. All columns in the underlying tables are prepended with the table name, so I can include two similarly named columns in the view by default. This alone solves my original problem, but I also included the "WHERE column_name NOT IN" clause to specifically exclude certain columns that will never be used in the MasterView.
create procedure Utility_RefreshMasterView
as
begin
declare #entity_columns varchar(max)
declare #drop_view_sql varchar(max)
declare #alter_view_definition_sql varchar(max)
/* create comma separated string of columns from underlying tables aliased to avoid name collisions */
select #entity_columns = stuff((
select ','+table_name+'.['+column_name+'] AS ['+table_name+'_'+column_name+']'
from information_schema.columns
where table_name IN ('entity_1', 'entity_2')
and column_name not in ('column to exclude 1', 'column to exclude 2')
for xml path('')), 1, 1, '')
set #drop_view_sql = 'if exists (select * from sys.views where object_id = object_id(N''[dbo].[MasterView]'')) drop view MasterView'
set #alter_view_definition_sql =
'create view MasterView as select ' + #entity_columns + '
from entity_1
inner join entity_2 on entity_2 .id = entity_1.id
/* other joins follow */'
exec (#drop_view_sql)
exec (#alter_view_definition_sql)
end
If you have a Select * and then you are using the JOIN, the result might include columns with the same name and that cannot be possible in a view.If you run the query by itself, works fine but not when creating the View.
For example:
**Table A**
ID, CatalogName, CatalogDescription
**Table B**
ID, CatalogName, CatalogDescription
**After the JOIN query**
ID, CatalogName, CatalogDescription, ID, CatalogName, CatalogDescription
That's not possible in a View.
Specify a unique name for each column in the view. Using just * is not a very good practice.

Resources