I’m a beginner to SQL and am struggling with the following:
I have two tables with the same columns except one column from table A is not a column of table B and table B has a column that table A doesn’t have. I want to copy data from
one into the other table.
I got the following SQL, that gives me the column-names of my table B:
SELECT name
FROM sys.columns
WHERE object_id = OBJECT_ID(’TABLEB’)
AND name <> COLUMNNOTINA
I want to use that select as a query:
SELECT
(SELECT name
FROM sys.columns
WHERE object_id = OBJECT_ID(’TABLEB’)
AND name <> COLUMNNOTINA), 0
FROM
TABLEA
This does not work, but how do I make this work?
Thank you in advance!
Let's say there is some common thing connecting the two tables
For example, ORDINAL_POSITION
T1.ORDINAL_POSITION = T2.ORDINAL_POSITION
Is there a description or property to compare each column?
select * from (
(SELECT name FROM sys.columns WHERE object_id = OBJECT_ID(’TABLEA’) ) as T1
Inner join
(SELECT name FROM sys.columns WHERE object_id = OBJECT_ID(’TABLEB’) ) as T2
ON T1.ORDINAL_POSITION = T2.ORDINAL_POSITION
)
Where T1.ColName <> T2.ColName
Related
I'm using SQL Server Management Studio 18.
I have a function that takes a table name as a parameter and outputs a table with info about other tables that have the same columns in it. Each table has a different amount of columns (that are also in other tables or not). The output is column names, table names and subject. This works.
I want to apply the same function to all tables that are in the result set of the first table I applied the function to, and union it with each other.
I know what I am doing wrong (dbo.TableStructure(firstTable.TableName)) doesn't work because the function is made for only 1 parameter and not multiple. But I don't know what to change to make it right.
The code of the function:
create function [dbo].[TableStructure](#table nvarchar(50))
returns table as return
(
select c.name as 'ColumnName', t.name as 'TableName', s.Subject as 'Subject'
from sys.columns c join sys.tables t on c.object_id = t.object_id join dbo.tableSubjects s on t.name=s.name
where t.name <> #table and c.name in (select name from sys.columns where object_id = (select object_id from sys.tables where name = #table)))
The code of applying the function:
declare #table varchar(50) = 'Example';
with firstTable as (select *, 1 as 'Counter' from dbo.TableStructure(#table));
union all
with tmpTable as (select *, 2 as 'Counter' from dbo.TableStructure(firstTable.TableName));
I think you just want cross apply:
with ts as (
select ts.*, 1 as Counter
from dbo.TableStructure(#table)
)
select ts.*
from ts
union all
select ts2.*, 2 as counter
from ts cross apply
dbo.TableStructure(ts.tablename) ts2;
I am using SQL Server 2017. How can I search for multiple column names in a single table?
I can search for a single column name (USERID) in my database with:
select *
from INFORMATION_SCHEMA.COLUMNS
where COLUMN_NAME like '%USERID%'
order by TABLE_NAME
But, I want to search for all tables that have both USERID and DOB.
Using:
select *
from INFORMATION_SCHEMA.COLUMNS
where COLUMN_NAME like '%USERID%' OR COLUMN_NAME like '%DOB%'
order by TABLE_NAME
returns a list of all tables that contain the column USERID as well as all tables that contain DOB.
Changing to AND results in a completely empty list, which is correct, as a single column would not contain both terms
You can try below -
select TABLE_NAME from INFORMATION_SCHEMA.COLUMNS
where COLUMN_NAME like '%USERID%' OR COLUMN_NAME like '%DOB%'
group by TABLE_NAME
having count(distinct COLUMN_NAME)=2
Below query will give you desired results:
;WITH cte
AS (SELECT object_id , ROW_NUMBER() OVER(PARTITION BY object_id
ORDER BY object_id) AS rn
FROM sys.columns AS c
WHERE c.name = 'USERID'
OR
c.name = 'DOB')
SELECT s.name + '.' + t.name
FROM sys.tables AS t INNER JOIN cte AS c ON t.object_id = c.object_id
INNER JOIN sys.schemas AS s ON t.schema_id = s.schema_id
WHERE c.rn > 1;
Please note to use exact column names with = operator and not like operator to get the correct results.
Sorry the title might be confusing but I will try to explain better here. So I have 2 tables.
Table1
Name
Int
Decimal
Table2
Name
Int
Decimal
I am trying to combine the data into a third table. It would look something like this
Table3
Name
Table1_Int
Table1_Decimal
Table2_Int
Table2_Decimal
The insert is not an issue. The issue is I have a few names that exist in one table and not the other. I still want these to show up, just with NULL values where there are no values.
Here is my stored proc
IF NOT EXISTS(
SELECT Name FROM Table3)
INSERT INTO Table3(
Name,
Table1_Int,
Table1_Decimal,
Table2_Int,
Table2_Decimal)
SELECT
t.Name,
AVG(t.Int) as Table1_Int,
AVG(CAST(t.Decimal as decimal(6,2))) as Table1_Decimal
AVG(a.Int) as Table2_Int,
AVG(CAST(a.Decimal as decimal(6,2))) as Table2_Decimal
FROM Table1 t
JOIN Table2 a
ON t.Name = a.Name
GROUP BY t.Name
ELSE
UPDATE Table3
SET Name = Name
Is there anyway I can grab all names, no matter if they match between tables?
I'd go with the basic logic of a FULL OUTER JOIN. I'd expect it to look something like this;
SELECT
COALESCE(t.name, a.name) name
,AVG(t.Int) t_int
,AVG(CAST(t.Decimal as decimal(6,2))) t_decimal
,AVG(a.Int) a_int
,AVG(CAST(a.Decimal as decimal(6,2))) a_decimal
FROM Table1 t
FULL OUTER JOIN Table2 a
ON t.name = a.name
GROUP BY COALESCE(t.name, a.name)
I have 81 tables where I want to find matching columns and output a list like:
"columnName" found in 3 tables:
table1
table2
table3
"columnName2" found in 4 tables:
table1
table3
table4
table5
The table INFORMATION_SCHEMA.COLUMNS is a system table which contains all columns for all tables. You can look at it by selecting from it.
For your question, you should try this :
select I.Column_name,
table_name,
table_count
from INFORMATION_SCHEMA.COLUMNS I
inner join
(
Select Column_name,
count(*) as table_count
from INFORMATION_SCHEMA.COLUMNS
group by Column_name) as T on T.Column_name = I.Column_name
You will have a table with, for each column_name, the tables, and the count in the column table_count.
I ust don't know how to output a list. You should put it on excel then if you want to format it I guess ..
Tell me if you have problem !
Below Query should give you the desired result. Let me know if you face any issues. You can modify script if you want to be specific about the single database
This query provides you Column Name - Concatinated Table Names - Number of Tables
SELECT t.CNAME AS ColumnName, STUFF(
(SELECT ',' + S.TNAME
FROM
(
SELECT C.NAME AS CNAME , T.NAME AS TNAME
FROM SYS.OBJECTS AS T
JOIN SYS.COLUMNS AS C
ON T.OBJECT_ID=C.OBJECT_ID
WHERE T.TYPE_DESC='USER_TABLE'
)s
WHERE s.CNAME = t.CNAME
FOR XML PATH('')),1,1,'') AS TablesUsed,
COUNT(t.TNAME)
FROM
(
SELECT C.NAME AS CNAME , T.NAME AS TNAME
FROM SYS.OBJECTS AS T
JOIN SYS.COLUMNS AS C
ON T.OBJECT_ID=C.OBJECT_ID
WHERE T.TYPE_DESC='USER_TABLE'
)t
GROUP BY t.CNAME
HAVING COUNT(t.TNAME) > 1
ORDER BY COUNT(t.TNAME) DESC
In SQL, I am joining a table onto itself:
SELECT * FROM table AS a
LEFT JOIN table AS b
ON a.NAME = b.NAME
So it's fetching all the rows which have the same NAME appearing in a row of the other table (will also return the same row twice!).
Let's say that I want to save the result into a temporary table, say something like:
SELECT * INTO ##temp_table FROM (
SELECT * FROM table AS a
LEFT JOIN table AS b
ON a.NAME = b.NAME
)
Oh dear. SQL says:
The column 'NAME' was specified multiple times.
Reason: SQL can only create a table if every column name is unique.
Obvious solution: give every column name in the "second table" an alias.
My problem is that the actual tables I'm working with have about 40 columns. Giving every one of those columns an alias seems like a wasteful use of time. Sure, I don't need every column so could drop some of them, but deciding which ones I require just now also seems wasteful.
Question: is there a shorthand way to rename every column? For example, can I append every column name with a _2 or an _a?
Ok, you have a query, with 2 joined tables, wich returns both tables columns (i don't care if you are joining the same table with itself).
So you have two possible results
Show both colums, with differents alias (AS)
SELECT * INTO ##temp_table FROM (
SELECT a.Name AS NameA, b.Name AS NameB FROM table AS a
LEFT JOIN table AS b
ON a.NAME = b.NAME
)
Or, if you don't want them duplicated (because the other will return two times the same name)
SELECT * INTO ##temp_table FROM (
SELECT a.Name FROM table AS a
LEFT JOIN table AS b
ON a.NAME = b.NAME
)
And what if you have more colums? Ok, you can just show one of the tables in the JOIN
SELECT * INTO ##temp_table FROM (
SELECT b.* FROM table AS a
LEFT JOIN table AS b
ON a.NAME = b.NAME
)
Sorry for my bad english! I hope this can help you!
I suggest querying sys.tables and sys.columns to get your renamed fields quickly:
SELECT c.name + '_2,' ColumnName
FROM sys.columns c
JOIN sys.tables t
ON c.object_id = t.object_id
WHERE t.name = 'YourTable'
Or you can combine with the OBJECT_ID() function:
SELECT c.name + '_2,' ColumnName
FROM sys.columns c
WHERE object_id = OBJECT_ID('YourTable')