Retrieve SQL View Column Metadata with Custom Query - sql

I created a SQL View and one of the column value is a SQL query for example 'SELECT TOP 1 value from TableB' with the column alias as 'Result'
I tried INFORMATION_SCHEMA.COLUMNS and the COLUMN_NAME only shown 'TableB'. How can I retrieve the 'SELECT TOP 1 value from TableB'?

IronManWK
I found something for you. You should try this :
SELECT M.definition
FROM sys.sql_modules M
WHERE M.object_id = (SELECT V.object_id FROM sys.views V WHERE V.name = 'vue_2')
Reminder, 'vue_2' is into my first answer.

I used SQL SERVER 2012
create table A (
id int identity(1,1),
data nvarchar(255),
)
;
INSERT A (data)
values ('A_ligne1'),('A_ligne2')
create table B (
id int identity(1,10),
data nvarchar(255),
date datetime default GetDate(),
)
;
INSERT B (data)
values ('B_ligne1'),('B_ligne2'),('B_ligne3'),('B_ligne4')
;
GO
CREATE VIEW vue_2
AS
SELECT A.*, (SELECT TOP 1 date FROM B) AS result
FROM A
;
When I make
SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'vue_2'
the result set is
TABLE_NAME COLUMN_NAME
vue_2 id
vue_2 data
vue_2 result
So, where is your problem ?

Related

How to interrogate multiple tables with different structure?

I am using Sql-Server 2016 in a C# application.
Let's say I have two tables:
CREATE TABLE Table_A
(
UserID NVARCHAR2(15),
FullName NVARCHAR2(25),
Available NUMBER(1),
MachineID NVARCHAR2(20),
myDate date
);
and
CREATE TABLE Table_B
(
UserID NVARCHAR2(15),
FullName NVARCHAR2(25),
Team NVARCHAR2(15),
MachineID NVARCHAR2(20),
Stuff NUMBER(2)
);
I want to perform a global select so that I will get as result data from both tables, somehow concatenated and of course, when a column does not exist in one of the tables, that column to be automatically populated with NULL, and if a column exists on both tables the results must be merged in a single column.
The first solution that pops-up is a UNION with NULL aliases for the missing columns, sure. The problem is that at runtime I will not be able to know in advance which tables are interrogated so that I could anticipate the column names. I need a more general solution.
The expected result from the two tables must look like this:
user_Table_A; fullName_Table_A; 1; machineID_Table_A; 12-JUN-18; NULL; 10;
user_Table_B; fullName_Table_B; NULL; machineID_Table_B; NULL; team_Table_B; 20;
The data for the two tables is inserted with the following commands:
INSERT INTO Table_A VALUES ('user_Table_A', 'fullName_Table_A', 1, 'machineID_Table_A', TO_DATE('12-06-2018', 'DD-MM-YYYY'));
INSERT INTO Table_B VALUES ('user_Table_B', 'fullName_Table_B', 'team_Table_B', 'machineID_Table_B', 20);
You can do something like this. I havent have time to completely tweak it, so there can be something the order of the columns. But perhaps it can get you started:
You also write that you use Oracle - Im not sure what you wanted, but this is in pure sql-server version.
SQL:
IF OBJECT_ID('tempdb..#temp') IS NOT NULL
/*Then it exists*/
DROP TABLE #temp;
GO
DECLARE #SQLList nvarchar(max)
DECLARE #SQLList2 nvarchar(max)
DECLARE #SQL nvarchar(max)
with table_a as (
select column_name as Table_aColumnName,ORDINAL_POSITION from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = 'table_a'
)
,
table_b as (
select column_name as Table_bColumnName,ORDINAL_POSITION from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = 'table_b'
)
,preresult as (
select case when Table_aColumnName IS null then 'NULL as ' + Table_bColumnName else Table_aColumnName end as Table_a_ColumnName,case when Table_bColumnName IS null then 'NULL as ' +Table_aColumnName else Table_bColumnName end as Table_b_ColumnName
,a.ORDINAL_POSITION,b.ORDINAL_POSITION as Table_b_Ordinal from table_a a full join Table_B b on a.Table_aColumnName = b.Table_bColumnName
)
select * into #temp from preresult
SET #SQLList = (
select distinct display = STUFF((select ','+table_a_columnName from #temp b order by table_b_ordinal FOR XML PATH('')),1,1,'') from #temp a
)
SET #SQLList2 = (
select distinct display = STUFF((select ','+table_b_columnName from #temp b order by Table_b_Ordinal FOR XML PATH('')),1,1,'') from #temp a
)
SET #SQL = 'select ' +#SQLList +' from dbo.Table_a union all select ' + #SQLList2 + ' from dbo.table_b'
exec(#SQL)
Result:

SQL copying record with out specifying column list; ignoring Identity

I'm trying to copy a record from TableA back to TableA, but using a new Identity.
I don't want to specify column list as I have over 100 columns, and there may be more in the future. Id like a chunk of code that can run when/if things change.
After looking similar questions, I have attempted this code
SELECT * INTO #tmp FROM TableA WHERE Id = 1;
ALTER TABLE #tmp DROP COLUMN Id;
INSERT INTO TableA SELECT * FROM #tmp;
Drop Table #tmp;
I am however still getting this error
An explicit value for the identity column in table 'dbo.TableA' can only be specified when a column list is used and IDENTITY_INSERT is ON.
Running a Select * FROM #tmp gives me what I would expect. A single record with all my Columns with the exception of the Id column.
Any Ideas?
Thanks!
EDIT
Here is a pictures of the properties of the Id Column
Use Dynamic SQL: get your list of columns (except ID), build an insert statement using that list, and then call exec on it:
SELECT *
INTO #tmp
FROM TableA
WHERE Id = 1;
ALTER TABLE #tmp DROP COLUMN id;
DECLARE #cols varchar(max);
SELECT
#cols = COALESCE(#cols + ',', '') + COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'TableA' AND COLUMN_NAME <> 'id'
--select #cols -- display column list for debugging
DECLARE #sqltxt varchar(max) = 'INSERT INTO TableA (' + #cols + ') SELECT * FROM #tmp';
--SELECT #sqltxt -- display the statement for debugging
exec (#sqltxt)
DROP TABLE #tmp
Try This
Step 1 :
INSERT INTO Employee1(FirstName,LastName,ManagerID,Salary)
SELECT FirstName,LastName,ManagerID,Salary
FROM Employee1
WHERE EmployeeID=X -- Your Emplyee ID
Step 2:
DELETE FROM Employee1 WHERE EmployeeID=X

How to list all columns in views with relations - SQL Server

I made a lot of views with 7-20 columns in each of them. I need to make a query which will return me the list of tables and columns on which is related every column in every view.
Example of my view:
CREATE VIEW example AS
SELECT t.NAME, t.AGE, t.ADDRESS, p.MOBILE, p.LAPTOP ...
FROM person t, device p
WHERE ...
Query result (needed):
TABLE COLUMN
person NAME
person AGE
person ADDRESS
device MOBILE
device LAPTOP
Is this possible, and how? It saves me a lot of time (there is over 900 columns in all views).
Thanks
Yet you can have this query to pull all the views present in your database along with columns present in them views.
SELECT v.name AS View_Name
,c.name AS Column_Name
FROM sys.views v
INNER JOIN sys.all_columns c ON v.object_id = c.object_id
Here is a more elaborated solution, the idea is to convert views to temp tables with no records (select top 0 * from ...) and for each table retrieve the column names from INFORMATION SCHEMA:
---Create this table First
CREATE TABLE dbo.Views_Columns(
id INT IDENTITY(1,1) PRIMARY KEY,
ViewName varchar(100),
ColumnName varchar(100)
)
--START
DECLARE #CurrentView varchar(100)
DECLARE #CurrentSchema varchar(50)
--Temp table #AllViews stores all views names
SELECT s.name as SchemaName, v.name as ViewName, 0 as Processed
INTO #AllViews
FROM sys.views v INNER JOIN SYS.schemas s ON v.schema_id = s.schema_id
WHILE EXISTS (select * from #AllViews WHERE Processed = 0)
BEGIN
--Clean up our temp table
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'temp')
BEGIN
DROP TABLE dbo.temp
END
SELECT TOP 1 #CurrentView = ViewName, #CurrentSchema = SchemaName
FROM #AllViews WHERE Processed = 0
EXEC('SELECT TOP 0 * INTO dbo.temp FROM '+#CurrentSchema+'.'+#CurrentView)
INSERT INTO Views_Columns
SELECT #CurrentSchema+'.'+#CurrentView, Column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'temp'
UPDATE #AllViews SET Processed = 1 where ViewName = #CurrentView
END
SELECT * FROM Views_Columns
--END

TSQL Subquery for Column Names?

Is it possible to use a set of query results for column names in a select statement?
Example, I have a table named TableA:
Column: Type:
KeyOne nvarchar(5)
KeyTwo nvarchar(5)
TableB is another table, whose column names might be stored in TableA.
Suppose TableB is like this:
Column: Type:
Val1 int
Val2 int
Is there any way I could do a query like this to get the columns?
SELECT (select TOP 1 KeyOne, KeyTwo FROM TableA)
FROM TableB
Another example using strings would be like this:
SELECT (select 'Val1', 'Val2')
FROM TableB
Is this possible in any way without concatenated SQL?
Unfortunately you can only do this with dynamic SQL, but it's pretty straightforward:
DECLARE #cols VARCHAR(MAX) = (SELECT TOP 1 KeyOne+','+KeyTwo FROM TableA)
,#sql VARCHAR(MAX)
SET #sql = 'SELECT '+#cols+' FROM TableB'
EXEC (#sql)
You can read table column names dynamically from sys.columns system views or using other management views
select name from sys.columns where object_id = object_id(N'TableName')
Then by creating a dynamic SQL query you can create your own select

SQL query for finding all tables ROWS with two columns in them

I have a DataBase with around +100 tables, like half of tables have column A & column B.
My question is, Can I query all tables that have this columns with a specific values e.g.
SELECT * FROM DATABASE
WHERE
EACHTABLE HAS COLUMN A = 21 //only if table has columns and then values
AND
COLUMN B = 13
I am not sure how exact I will do it, nothing is coming up on google either
You can use the undocumented MS stored procedure sp_MSforeachtable, if you fancy living life recklessly:
create table T1 (
ColumnA int not null,
ColumnB int not null
)
go
create table T2 (
ColumnA int not null,
Column2 int not null
)
go
create table T3 (
Column1 int not null,
ColumnB int not null
)
go
create table T4 (
ColumnA int not null,
ColumnB int not null
)
go
insert into T1 values (1,2);
insert into T2 values (3,4);
insert into T3 values (5,6);
insert into T4 values (7,8);
go
create table #Results (TableName sysname,ColumnA int,ColumnB int)
exec sp_MSforeachtable 'insert into #Results select ''?'',ColumnA,ColumnB from ?',
#whereand = ' and syso.object_id in (select object_id from sys.columns where name=''ColumnA'') and syso.object_id in (select object_id from sys.columns where name=''ColumnB'')'
select * from #Results
drop table #Results
Result:
TableName ColumnA ColumnB
------------------------------------- ----------- -----------
[dbo].[T1] 1 2
[dbo].[T4] 7 8
By default, sp_MSforeachtable will, as its name implies, perform the same task for each table in the database. However, one optional parameter to this procedure, called #Whereand, can be used to modify the WHERE clause of the internal query that enumerates the tables in the database. It helps to know that this internal query has already established two aliases to some of the system views. o is an alias for sysobjects (the legacy system view). syso is an alias for sys.all_objects (a more modern system view).
Once sp_MSforeachtable has decided which tables to run against, it will execute the query given to it as its first parameter. But, it will replace ? with the schema and table name (? is the default replacement character. This can be changed as needed)
In this case, I chose to create a temp table, then have each selected table store its results into this temp table, and after sp_MSforeachtable has finished running, to select the combined results out with no further processing.
There is a similar (and similarly undocumented) procedure called sp_MSforeachdb which will access each user database on the server. These can even be combined (although you have to be careful with doubling up ' quote characters twice, at times). However, there's no equivalent sp_MSforeachcolumn.
Try this:
select t.name from sys.objects t inner join sys.columns c
on t.name=OBJECT_NAME(c.object_id)
where t.type='U'
and c.name in('col1','col2')
group by t.name
having COUNT(*) = 2
order by 1
Then you just loop through all the tables and fine the values for these columns.
Like
Declare #out TABLE(tblname varchar(100))
if exists(select * from tbl1 where col1='21' and col2='22')
BEGIN
INSERT INTO #out
select tbl1
END
You can try like this using dynamic query.
select 'select * from '+table_name+ ' where'+column_name+'=21'
from information_schema.columns where column_name = 'A'
I suggest to use two steps:
First, find out all tables in your database that have these two columns and use it for a temporal derived table. For I am not an expert in SQL-Server 2008 I recommend to have a look at the whitepages.
The expression might look like this:
SELECT tablename
FROM information_schema.tables sdbt
WHERE "column a" IN
(SELECT columns
FROM information_schema.columns col
WHERE col.tablename = sdbt.tablename)
Second, use a expresssion to filter the results according to your demanded values.
This command should do the trick in one go, only for column A, amend accordingly to include any other columns you need:
exec sp_MSforeachtable
#command1=N'SELECT * FROM ? WHERE A = 21',
#whereand=' and o.name IN (SELECT TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME = ''A'') '