I am working on a project whos purpose is to rename all table names and column names in the sql database from one language to another. I have gather all the local table names into a table ltbl_TableNames and want to add all the columns of these tables into a table called ltbl_TableColumns.
I also want every table column to have a link to their table name. For example, the table 'Sales' have a column named 'Sum'. The table 'Sales' has the ID '10000'. I want to add that ID in a column named 'TableName_ID' for linking purposes. Is this possible to do without a lot of hassle?
Disclaimer: I am thinking about the renaming process. I only want to gather the column names with link to their parent table name.
Thanks in advance for answers.
You may use sys.tables for getting list of table name in your database.
Similarly for column name you may use information_schema.columns as this will give records with table name.
From the above 2 records you can easily make you required result.
;WITH CTABLE AS
( SELECT * FROM SYS.TABLES WHERE TYPE_DESC = 'USER_TABLE' )
, COLUMNNAME AS
( SELECT * FROM INFORMATION_SCHEMA.COLUMNS )
SELECT * INTO NEWTABLE FROM
(SELECT CTABLE.NAME AS TABLENAME , COLUMNNAME.COLUMN_NAME, COLUMNNAME.COLUMN_NAME + '_' + CAST(CTABLE.OBJECT_ID AS VARCHAR(15)) AS NEW_COLUMNNAME
FROM CTABLE INNER JOIN COLUMNNAME ON CTABLE.NAME = COLUMNNAME.TABLE_NAME ) AS D
You may try this for your result.
Related
I currently import a file dynamically using SSIS into a SQL table, part of the process imports the column headers from the source file into the first row of a table (table 1 below).
I then want to compare the headers from table 1 with table 2 which has static columns, and most importantly highlight any column headers from table 1 that do not exist in table 2.
So for example Table 1 looks like this:
Column 1
Column 2
CustomerID
CustomerName
And table 2 has static column headers like the following:
CustomerID
CustomerName
1
Joe
2
Daniel
So basically when I load a file and a new column header is added (in this example lets say CustomerLocation is added) and loaded into table 1, I want a SQL query to compare the 2 tables and highlight that the column CustomerLocation is missing/does not exist in table 2 currently.
I was thinking along the lines of using the sys tables to compare.
You certainly could use sys.columns to return your static columns from Table2 and compare them to the dynamic columns in Table1 and use UNPIVOT on a select of your first row.
I have found that it was far easier to wrap this all in a T-SQL block and insert to two lists into temp tables before comparing due to data type conflicts (probably be solved by using CAST)
BEGIN
DECLARE #table1 TABLE (colname VARCHAR(MAX))
DECLARE #table2 TABLE (colname VARCHAR(MAX))
INSERT INTO #table1 SELECT COLNAME FROM (SELECT a, b, c FROM TABLE1 WHERE...first row condition) a UNPIVOT (COLNAME FOR COLS IN ([a],[b],[c])) a
INSERT INTO #table2 SELECT CAST (name AS NVARCHAR(100)) name FROM sys.columns WHERE object_id = OBJECT_ID('TABLE2')
SELECT a.colname cols1, b.colname cols2
FROM #table2 a
FULL OUTER JOIN #table1 b ON (a.colname = b.colname)
END
You can easily change the final select to return what you want
I want to select total 450 fixed columns from the table which may or may not have all 450 columns always. When it doesn't have all columns then it should create the missing column and set it's value as null.
In Sql there is a function
if exists()
But in bigquery I am unable to use it wisely.
Any suggestion will help a lot
I assume in the following that you have a source table (the one with potentially "missing" columns) and an existing target table (with the desired schema).
In order to get the information of the columns of these tables, you just need to look into the INFORMATION_SCHEMA.COLUMNS table.
The solution below uses dynamic SQL, to 1) generate the desired SQL, 2) run it.
DECLARE column_selection STRING;
SET column_selection = (
WITH column_table AS (
SELECT
source.column_name AS source_colum,
tgt.column_name AS target_column
FROM
(SELECT
column_name
FROM `<yourproject>.<target_dataset>.INFORMATION_SCHEMA.COLUMNS`
WHERE table_name='<target_table>') tgt
LEFT JOIN
(SELECT column_name
FROM `<yourproject>.<source_dataset>.INFORMATION_SCHEMA.COLUMNS`
WHERE table_name='<source_table>') source
ON source.column_name = tgt.column_name
)
SELECT STRING_AGG(coalesce(source_column,
CONCAT("NULL AS `",target_column, "`")), ", \n") AS col_selection
FROM
column_table
)
EXECUTE IMMEDIATE
FORMAT("SELECT %s FROM `<yourproject>.<source_dataset>.<source_table>`", column_selection) ;
Explanation of the steps
Build a column_table for the columns we want to query:
a. first column containing the columns of the target table,
b. second one containing the corresponding source columns if they exist, or NULL if they don't
Once we have this table, we can build the desired SELECT statement: the name of the column is it's in the source table, or if it's NOT present, we want to have in our query " NULL AS `column_name_in_target` "
This is expressed in the
coalesce(source_column, CONCAT("NULL AS ``",target_column, "\``"))
We aggregate all these statement with STRING_AGG into the desired column selection.
Final step: putting together the rest of the query ( "SELECT" + <column_selection_string> + "FROM <your_source_table>" + ...), and we can EXECUTE IMMEDIATE it.
I got an error while creating an empty table by joining two tables.
I have two tables tab1 & tab2 and there are many common columns names in both tables.
I tried this:
create table tab3 as
select * from tab1 a, tab2 b where a.id = b.id and 1=2;
This gave ORA-00957: duplicate column name. As I mentioned above there are many common columns name between these two tables. If I prepare a create table statement by writing around 500 column names one by one then it will consume lots of time. Please help me out here.
The simple answer is, don't use *. Or is that the whole point, to avoid writing five lines of column names?
One way to avoid these conflicts, but that assumes that you are joining on all columns with the same name in both tables and on no other columns, is to do something like
create table new_table as
select *
from table_a natural join table_b
where null is not null
;
(As you can guess, as an aside, I prefer null is not null to 1 = 2; the parser seems to prefer it too, as it will rewrite 1 = 2 as null is not null anyway.)
Will you need to control the order of the columns in the new table? If you do, you will need to write them out completely in the select clause, regardless of which join syntax you choose to use.
That's an interesting question.
The only idea I have to offer it to let another query to compose the query you need
select 'select ' || listagg(col_name, ', ') within group(order by 1) || 'from tab1 a,tab2 b where (a.id=b.id) and 1=2'
from (select 'a.' || column_name col_name from user_tab_cols where table_name = 'TAB1'
union all
select 'b.' || column_name from user_tab_cols where table_name = 'TAB2')
Please be aware for subqueries you need to specify table names in the upper case
I have one table CONFIG_PRAM which contains columns like colname , datatype and many more details of existing tables.
Example
CREATE TABLE CONFIG_PRAM
( colname varchar(40),
datatype varchar(40)
);
I have to compare those columns and datatype present in CONFIG_PRAM table with the existing table`s columns.
Example: I have one existing table test1 table in database
create table test1 ( employee_id NUMBER(6),
sal NUMBER(6,8));
And if I found any mismatch I need to update CONFIG_PRAM table with correct data type.
FOR above one in CONFIG_PRAM table we have sal number
but actually it is number(6,8) in table so I have to update CONFIG_PRAM table with exact datatype.
I have tried like this:
select distinct colname , datatype
from CONFIG_PRAM , all_tab_columns
where upper(column_name)=upper(colname )
and data_type=datatype
and table_name in ('TEST1')
But Suppose Table A has Number(6,8)
and CONFIG_PRAM table contain only Number
then it is not giving correct results.
Issue is this query is not comparing decimal values exactly. Can you please provide a solution for this in sql/PLSQL?
This query joins your table to ALL_TAB_COLUMNS on the basis of COLUMN_NAME. This means it only works properly when CONFIG_PRAM has entries for just the one table. Perhaps it needs a column for TABLE_NAME as well?
select cp.colname
, cp.datatype as config_datatype
, atc.data_type as actual_datatype
, atc.data_length as actual_length
, atc.data_precision as actual_precision
, atc.data_scale as actual_scale
from CONFIG_PRAM cp
join all_tab_columns atc
on atc.column_name = cp.colname
where atc.owner = user
and atc.table_name in ('TEST1')
and upper(cp.datatype) != case
when atc.data_type = 'VARCHAR2'
then atc.data_type||'('||atc.data_length||')'
when atc.data_type = 'NUMBER'
and instr(cp.datatype, ',') = 0
and atc.data_scale = 0
then atc.data_type||'('||atc.data_precision||')'
when atc.data_type = 'NUMBER'
then atc.data_type||'('||atc.data_precision||','||atc.data_scale||')'
else atc.data_type
end
;
The WHERE clause compares your datatype column with an assembled datatype string. Obviously there are more potential datatypes than this query handles. You will need to extend it as necessary. Also, variations in the formatting of the datatype string will produce false positives. So you should have a proper think about the structure of your CONFIG_PRAM table: the looser the rules you apply on insert or update the more work you have to do when it comes to selecting it for use.
Here is a SQL Fiddle demo.
ALL_TAB_COLUMNS contains many more columns than just data_type. You will also need to compare at the very least data_length, data_precision and data_scale.
Your join is also missing table_name and owner, and it is better to use ANSI join syntax.
I've used a script to create a view that has the table name for every table in a database, along with the number of rows of data in the respective table. Everything works fine with SELECT *. However, I'd like to query only certain rows, but I can't seem to do that.
The view was created with the following script (credit to DatabaseZone.com for the script):
CREATE VIEW RowCount_AllTables
AS
SELECT DISTINCT
sys.schemas.name, sys.tables.name AS tableName,
sys.dm_db_partition_stats.row_count AS 'RowCount'
FROM
sys.tables
INNER JOIN
sys.dm_db_partition_stats ON sys.tables.object_id = sys.dm_db_partition_stats.object_id
INNER JOIN
sys.schemas ON sys.tables.schema_id = sys.schemas.schema_id
WHERE
(sys.tables.is_ms_shipped = 0)
When I run Select * against the resulting view, I get results such as:
name tableName RowCount
dbo Table1 2
dbo Table2 1230
dbo Table3 0
If I query just the tableName column, that works fine and returns the table names. However, if I try to query the RowCount column as well, I get the error message Incorrect syntax near the keyword 'RowCount. This happens regardless of whether I qualify the database -- it seems to not recognize RowCount as a valid column that I can call in a query. So this script fails:
SELECT RowCount
FROM RowCount_AllTables;
But this one works:
SELECT tableName
FROM RowCount_AllTables;
What's going on? I'd like to be able to alias the column names in the view in my query but I can't do that so long as I can't reference the RowCount column.
(FYI running this in SQL Server 2014)
Rowcount is a reserved word, you can select reserved words using [] as:
[Rowcount]
Thanks to #sgeddes for pointing the way. Dropped the view, changed the script for creating it to use another name for the row count column, and it now works as expected. The issue was a conflict with Rowcount being a reserved word.
Changed the create table script on this line:
SELECT distinct sys.schemas.name, sys.tables.name AS tableName,
sys.dm_db_partition_stats.row_count AS 'RowCount'
to:
SELECT distinct sys.schemas.name, sys.tables.name AS tableName,
sys.dm_db_partition_stats.row_count AS 'Row_Count'
...at which point I can now reference the Row_Count column as desired.