I have a table with 700 columns. I am trying to get a list of distinct values for each column and their count. I am using the below query to get the result for 1 column
Select distinct col1, count(*) from MyTable group by 1.
Result:
col1 count(*)
a 10
b 20
c 40
How can I get the result for all columns using a single query in the most optimal way?
The basic query is:
select col001, count(*) from MyTable group by col001 union all
select col002, count(*) from MyTable group by col002 union all
. . .
select col700, count(*) from MyTable group by col700 ;
Not pleasant, but that is basically the query you need to run. SQL doesn't really do multiple independent aggregations more efficiently than doing them separately (even using grouping sets, in my experience).
You can construct the query. One way is to run something like this:
select replace(replace('select [col], count(*) as cnt from [tab] group by [col] union all ',
'[tab]', table_name
), '[col]', column_name
)
from information_schema.columns
where table_name = 'mytable' and table_schema = ??;
You can then copy the generated SQL (removing the final union all) and run it.
Note: That above is generic; the exact code might differ by database.
A list with distinct values for each column is impossible. What if column A has 5 distinct values and column B has 7. What would your list look like?
The other question is easier, but as #Gordon Linoff states, takes 2 steps. Elaborating on his answer, for MS SQL:
select replace(replace(' count(distinct([col])) as [col],',
'[tab]', table_name
), '[col]', column_name
)
from information_schema.columns
where table_name = 'your_table';
Copy the results and paste them in a new query window between.
SELECT
[[results query 1]]
FROM your_table
Remember to delete the last ',' from query 1 results.
Replace [table name] with the table you need counts for.
DECLARE #table varchar(100) = '[table name]'
DECLARE #i INT = 1, #cntOUT int, #SQL nvarchar(500) = ''
DECLARE #ParmDef nvarchar(500) = N'#cnt int OUTPUT';
SELECT column_id, name, 0 as record_count
INTO #T1
FROM sys.all_columns c
WHERE c.object_id = (SELECT object_id FROM sys.objects WHERE name = #table AND type = 'U')
WHILE #i <= (SELECT MAX(column_id) FROM #T1)
BEGIN
SELECT #SQL = 'SELECT #cnt = COUNT(DISTINCT ' + name + ') FROM ' + #table + ';'
FROM #T1 WHERE column_id = #i;
EXECUTE sp_executesql #stmt = #SQL, #ParmDefinition = #ParmDef, #cnt = #cntOUT OUTPUT;
UPDATE #T1 SET record_count = #cntOUT WHERE column_id = #i
SET #i = #i + 1
END
SELECT * FROM #T1
--DROP TABLE #T1
Related
I have a table with hundreds of columns:
------------------------------------------------
ID ColA ColB ColC Col D ... ColZZZ
------------------------------------------------
1 bla
2 foo
3 bar
4 baz
------------------------------------------------
I need to know which columns have no values in them (that is: which are empty '' not NULL)
I could create a query for every column:
select count(1) from [table] where [ColA] <> ''; -- returns 2, so not, not empty
select count(1) from [table] where [ColB] <> ''; -- returns 1, so no
select count(1) from [table] where [ColC] <> ''; -- returns 0, so yay! found and empty one
...
etc
But there has to be an easier way for this?
Is there a way to return [table] without the empty columns, in other words:
----------------------------
ID ColA ColB ColZZZ
----------------------------
1 bla
2 foo
3 bar
4 baz
----------------------------
Here is solution to it. I used this query before too search for empty columns across all tables. Slightly modified now to search for non-empty, it might have few extra parts not needed in you example.
You create a temp table to store column names that are not empty, and use cursor to create dynamic sql to search for them.
In the end, just generate another dynamic sql to select columns based on temp table results.
IF (OBJECT_ID('tempdb..#tmpRez') IS NOT NULL) DROP TABLE #tmpRez;
CREATE TABLE #tmpRez (TableName sysname, ColName sysname);
DECLARE crs CURSOR LOCAL FAST_FORWARD FOR
SELECT t.name, c.name FROM sys.tables t
INNER JOIN sys.columns c ON c.object_id=t.object_id
WHERE 1=1
AND t.name = 'Table1' -- OR your own condition
OPEN crs;
DECLARE #tbl sysname;
DECLARE #col sysname;
DECLARE #sql NVARCHAR(MAX);
FETCH NEXT FROM crs INTO #tbl,#col;
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #sql = 'IF EXISTS (SELECT * FROM ['+ #tbl+'] WHERE [' + #col + '] <> '''') INSERT INTO #tmpRez SELECT ''' + #tbl +''','''+ #col + '''';
EXEC(#sql);
FETCH NEXT FROM crs INTO #tbl,#col;
END;
CLOSE crs;
DEALLOCATE crs;
SELECT #sql = 'SELECT ' + STUFF((SELECT ',' + ColName FROM #tmpRez x
where x.TableName = y.TableName
FOR XML PATH ('')), 1, 1, '') + ' FROM ' + TableName
FROM #tmpRez y GROUP BY TableName
EXEC (#sql)
How about this to return the table with no empty columns:
SELECT * from table
WHERE column IS NOT NULL AND TRIM(column) <> ''
This to return the table with empty columns:
SELECT * from table
WHERE column IS NULL AND TRIM(column) = ''
I'd like to create a dynamic select that returns every distinct value for each column in a wide table. I.e.
select distinct #mycolumn
from #mytable
for every column and the results combined to a single table.
Edit1:
Example:
Edit2: The order of the returned data won't matter, and the source table can have all sorts of data types.
Any advice appreciated, thank you!
The only way I can think of is very cumbersome and probably extremely slow:
Using a Tally table (I've generated one using a recursive cte for the sake of this answer, but that's also not a very good way to do that...) and multiple derived tables left joined to that tally table I was able to come up with something that will generate the desired output.
However, as I wrote on the top - it's very cumbersome and probably extremely slow (I've tested only on a table with 5 columns and 6 rows so I have no idea about execution speed).
DECLARE #Count int
select #Count = COUNT(1)
FROM YourTable
;with tally as (
select 1 as n
union all
select n + 1
from tally
where n < #Count
)
SELECT Column1, Column2, Column3, Column4, Column5
FROM tally
LEFT JOIN
(
SELECT Column1, ROW_NUMBER() OVER (ORDER BY Column1) rn
FROM
(
SELECT DISTINCT Column1
FROM YourTable
) t1
) d1 ON(n = d1.rn)
LEFT JOIN
(
SELECT Column2, ROW_NUMBER() OVER (ORDER BY Column2) rn
FROM
(
SELECT DISTINCT Column2
FROM YourTable
) t1
) d2 ON(n = d2.rn)
LEFT JOIN
(
SELECT Column3, ROW_NUMBER() OVER (ORDER BY Column3) rn
FROM
(
SELECT DISTINCT Column3
FROM YourTable
) t1
) d3 ON(n = d3.rn)
LEFT JOIN
(
SELECT Column4, ROW_NUMBER() OVER (ORDER BY Column4) rn
FROM
(
SELECT DISTINCT Column4
FROM YourTable
) t1
) d4 ON(n = d4.rn)
LEFT JOIN
(
SELECT Column5, ROW_NUMBER() OVER (ORDER BY Column5) rn
FROM
(
SELECT DISTINCT Column5
FROM YourTable
) t1
) d5 ON(n = d5.rn)
Dynamic version:
DECLARE #TableName sysname = 'YourTableName'
DECLARE #Sql nvarchar(max) =
'
DECLARE #Count int
select #Count = COUNT(1)
FROM '+ #TableName +'
;with tally as (
select 1 as n
union all
select n + 1
from tally
where n < #Count
)
SELECT '
SELECT #Sql = #Sql + Column_Name +','
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #TableName
SELECT #Sql = LEFT(#Sql, LEN(#Sql) - 1) + ' FROM tally t'
SELECT #Sql = #Sql + ' LEFT JOIN (SELECT '+ Column_Name +', ROW_NUMBER() OVER (ORDER BY ' + Column_Name +') rn
FROM
(
SELECT DISTINCT '+ Column_Name +' FROM '+ #TableName +') t
) c_'+ Column_Name + ' ON(n = c_'+ Column_Name + '.rn)'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #TableName
EXEC(#Sql)
Update
Tested on a table with 22 columns and 47,000 rows, my suggestion took 46 seconds when using a proper tally table. on Sql server 2014.
I was surprised - I thought it would take at least 2-3 minutes.
Here's a dynamic set I was working on. I'm running out of time so it's not cleaned up, and it determines the dynamic row numbers by the max number of rows in the table as a whole, meaning that if you have any duplicates in any column at all, you'll be left with rows where every single column is null.
But other than that, this should work perfectly fine, and the script contains the necessary info showing you how to concatenate a final "WHERE S1.COLNAME IS NOT NULL AND S2.COLNAME IS NOT NULL AND .." filter to the result table, to eliminate those full-null rows.
Other than that, here's the script. It's gonna be heavy, obviously, so I included a (nolock) hint in it, and a "WHERE ColName is not null" to remove useless results.
Try this on a smaller table and see it work.
/*
Set your table and schema on #MYTABLE and #MYSCHEMA variables.
*/
SET NOCOUNT ON
DECLARE #MYTABLE SYSNAME = 'Mytablename here'
, #MYSCHEMA sysname = 'dbo'
DECLARE #SQL NVARCHAR(MAX) = '', #COLNAME sysname = '', #MYCOLS NVARCHAR(max) = ''
DECLARE #COL_NOW INT = 1, #COL_MAX INT =
(SELECT COUNT(*)
FROM sys.columns
WHERE object_id = (SELECT object_id FROM sys.tables where name = #MYTABLE and SCHEMA_NAME(schema_id) = #MYSCHEMA))
SELECT #COLNAME = name
FROM sys.columns
WHERE column_id = 1
and object_id = (SELECT object_id FROM sys.tables where name = #MYTABLE and SCHEMA_NAME(schema_id) = #MYSCHEMA)
SET #SQL = 'FROM
(SELECT ROW_NUMBER() OVER (ORDER BY '+#COLNAME+' ASC) RN
FROM '+#MYSCHEMA+'.'+#MYTABLE+' (nolock)) S'
WHILE #COL_NOW <= #COL_MAX
BEGIN
SELECT #COLNAME = name
FROM sys.columns
WHERE column_id = #COL_NOW
and object_id = (SELECT object_id FROM sys.tables where name = #MYTABLE and SCHEMA_NAME(schema_id) = #MYSCHEMA)
SELECT #SQL = #SQL+'
FULL JOIN
(SELECT DISTINCT DENSE_RANK() OVER (ORDER BY '+#COLNAME+' ASC) RN, '+#COLNAME+'
FROM '+#MYSCHEMA+'.'+#MYTABLE+' (nolock)
WHERE '+#COLNAME+' IS NOT NULL) S'+CAST(#COL_NOW AS NVARCHAR(25))+' ON S'+CAST(#COL_NOW AS NVARCHAR(25))+'.RN = S.RN'
IF #COL_NOW = 1
SELECT #MYCOLS = #MYCOLS+' S'+CAST(#COL_NOW AS NVARCHAR(25))+'.'+#COLNAME
ELSE
SELECT #MYCOLS = #MYCOLS+', S'+CAST(#COL_NOW AS NVARCHAR(25))+'.'+#COLNAME
SET #COL_NOW = #COL_NOW+1
END
SELECT #SQL = 'SELECT'+#MYCOLS+'
'+#SQL+'
ORDER BY S1.RN ASC';
--PRINT(#SQL); -- To check resulting dynamic SQL without executing it (Warning, print will only show first 8k characters)
EXEC sp_executesql #SQL;
GO
Background: I need to write a function in T-SQL on SQL Server 2008 10.0.5869.
Here's the table I'm working on (for the sake of simplicity - I only put in 3 columns here - but I have 10 columns for the actual work):
ID | Column1 | Column2 | Column3
1 | 2014-05 | 2015-02 | 2013-04
2 | 2012-09 | 2011-02 | 2013-03
ID is varchar and Column(x) are all datetime.
My end goal is to design a function fn_CompareDate to do something like this:
select fn_CompareDate(ID) from table where ID = 1
The query above should return the latest date from Column(x)s which should be 2015-02.
I used CASE WHEN but it would be almost impossible to use it for 10 columns. Is there another way to achieve the same result?
One approach is to use apply:
select d.maxd
from table t cross apply
(select max(d) as maxd
from values ((id, column1), (id, column2), (id, column3)) as val(id, d)
where val.id = t.id
) d
where t.id = 1;
EDIT:
You can do this without values():
select d.maxd
from table t cross apply
(select max(d) as maxd
from (select id, column1 as d union all
select id, column2 union all
select id, column3 union all
select id, column4
) val
where t.id = val.id
) d
where t.id = 1;
I think the below Function serves requirment better
CREATE FUNCTION fn_CompareDate(#ID VARCHAR(10))
RETURNS DATETIME
AS
BEGIN
DECLARE #maxDate DATETIME;
SELECT #maxDate =
(SELECT Max(v)
FROM (VALUES (COLUMN1), (COLUMN2), (COLUMN3)) AS value(v))
FROM table
WHERE ID = #ID
RETURN #maxDate;
END;
Now run the below query
select dbo.fn_CompareDate(ID) from table where ID = 1
Hope you got it.
You can use dynamic sql and INFORMATION_SCHEMA.COLUMNS. It supposed to work in SQL Server 2008. Try this:
CREATE PROCEDURE sp_CompareDate
#ID int,
#tableName NVARCHAR(MAX) = 'table2', -- Your table name
#dbName NVARCHAR(MAX) = 'temp' -- Your database name
AS
BEGIN
DECLARE #maxFieldValue DATETIME
DECLARE #curFieldName NVARCHAR(MAX)
DECLARE #curFieldValue DATETIME
DECLARE #sql NVARCHAR(MAX)
DECLARE fieldCursor CURSOR FOR
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #tableName
AND TABLE_CATALOG = #dbName AND COLUMN_NAME != 'ID'
OPEN fieldCursor
FETCH NEXT FROM fieldCursor INTO #curFieldName
SET #sql = N'USE [' + #dbName + N'] SELECT #curDate=' + #curFieldName
+ N' FROM ' + #tableName + N' WHERE ID=' + CAST(#ID AS NVARCHAR)
EXEC sp_executesql #sql, N'#curDate DATETIME output', #curFieldValue output;
SET #maxFieldValue = #curFieldValue
WHILE (##FETCH_STATUS = 0)
BEGIN
SET #sql = N'USE [' + #dbName + N'] SELECT #curDate=' + #curFieldName
+ N' FROM ' + #tableName + N' WHERE ID=' + CAST(#ID AS NVARCHAR)
EXEC sp_executesql #sql, N'#curDate DATETIME output', #curFieldValue output;
FETCH NEXT FROM fieldCursor INTO #curFieldName
IF (#maxFieldValue < #curFieldValue) SET #maxFieldValue = #curFieldValue
END
CLOSE fieldCursor;
DEALLOCATE fieldCursor;
SELECT #maxFieldValue
END
Hope this helps.
I found the 2nd solution from this question works quite well for me:
Create a function similar to this:
select max(col) from
(
select column1 [col] from table where id = #id
union all
select column2 from table where id = #id
union all
select column3 from table where id = #id
)
When we do SELECT * FROM table we get all records in a table, If I want to get only a row but do not know the number of columns
like
id att1 att2 att3.... attx
-------------------------------
1 45 5 3 7
How do I do a select statement that returns all columns?
I know I must use
from INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'myTable'
and a Where clause: WHERE id = 1
but again I do not know the number of columns...
Just add a where clause to the end of the #sql statement to limit your selection to the rows you want:
declare #cols nvarchar(max)
select #cols = coalesce(#cols + ', ' + column_name, column_name)
from information_schema.COLUMNS
where TABLE_NAME = 'mytable'
declare #sql nvarchar(max)
select #sql = 'select ' + #cols + ' from myTable where Id = 1'
exec sp_executesql #sql
The * means that you want all columns, not all "records".
select *
from YourTable
where ID = 1
There is no need to know the number of columns if you are interesting in pulling out the details of all. Just give the where condition with select *.
Is there any SQL lingo to return JUST the first two columns of a table WITHOUT knowing the field names?
Something like
SELECT Column(1), Column(2) FROM Table_Name
Or do I have to go the long way around and find out the column names first? How would I do that?
You have to get the column names first. Most platforms support this:
select column_name,ordinal_position
from information_schema.columns
where table_schema = ...
and table_name = ...
and ordinal_position <= 2
There it´s
declare #select varchar(max)
set #select = 'select '
select #select=#select+COLUMN_NAME+','
from information_schema.columns
where table_name = 'TABLE' and ordinal_position <= 2
set #select=LEFT(#select,LEN(#select)-1)+' from TABLE'
exec(#select)
A dynamic query using for xml path will also do the job:
declare #sql varchar(max)
set #sql = (SELECT top 2 COLUMN_NAME + ',' from information_schema.columns where table_name = 'YOUR_TABLE_NAME_HERE' order by ordinal_position for xml path(''))
set #sql = (SELECT replace(#sql +' ',', ',''))
exec('SELECT ' + #sql + ' from YOUR_TABLE_NAME_HERE')
I wrote a stored procedure a while back to do this exact job. Even though in relational theory there is no technical column order SSMS is not completely relational. The system stores the order in which the columns were inserted and assigns an ID to them. This order is followed using the typical SELECT * statement which is why your SELECT statements appear to return the same order each time. In practice its never a good idea to SELECT * with anything as it doesn't lock the result order in terms of columns or rows. That said I think people get so stuck on 'you shouldn't do this' that they don't write scripts that actually can do it. Fact is there is predictable system behavior so why not use it if the task isn't super important.
This SPROC of course has caveats and is written in T-SQL but if your looking to just return all of the values with the same behavior of SELECT * then this should do the job pretty easy for you. Put in your table name, the amount of columns, and hit F5. It returns them in order from left to right the same as you'd be expecting. I limited it to only 5 columns but you can edit the logic if you need any more. Takes both temp and permanent tables.
EXEC OnlySomeColumns 'MyTable', 3
/*------------------------------------------------------------------------------------------------------------------
Document Title: The Unknown SELECT SPROC.sql
Created By: CR
Date: 4.28.2013
Purpose: Returns all results from temp or permanent table when not knowing the column names
SPROC Input Example: EXEC OnlySomeColumns 'MyTable', 3
--------------------------------------------------------------------------------------------------------------------*/
IF OBJECT_ID ('OnlySomeColumns', 'P') IS NOT NULL
DROP PROCEDURE OnlySomeColumns;
GO
CREATE PROCEDURE OnlySomeColumns
#TableName VARCHAR (1000),
#TotalColumns INT
AS
DECLARE #Column1 VARCHAR (1000),
#Column2 VARCHAR (1000),
#Column3 VARCHAR (1000),
#Column4 VARCHAR (1000),
#Column5 VARCHAR (1000),
#SQL VARCHAR (1000),
#TempTable VARCHAR (1000),
#PermanentTable VARCHAR (1000),
#ColumnNamesAll VARCHAR (1000)
--First determine if this is a temp table or permanent table
IF #TableName LIKE '%#%' BEGIN SET #TempTable = #TableName END --If a temporary table
IF #TableName NOT LIKE '%#%' BEGIN SET #PermanentTable = #TableName END --If a permanent column name
SET NOCOUNT ON
--Start with a few simple error checks
IF ( #TempTable = 'NULL' AND #PermanentTable = 'NULL' )
BEGIN
RAISERROR ( 'ERROR: Please select a TempTable or Permanent Table.',16,1 )
END
IF ( #TempTable <> 'NULL' AND #PermanentTable <> 'NULL' )
BEGIN
RAISERROR ( 'ERROR: Only one table can be selected at a time. Please adjust your table selection.',16,1 )
END
IF ( #TotalColumns IS NULL )
BEGIN
RAISERROR ( 'ERROR: Please select a value for #TotalColumns.',16,1 )
END
--Temp table to gather the names of the columns
IF Object_id('tempdb..#TempName') IS NOT NULL DROP TABLE #TempName
CREATE TABLE #TempName ( ID INT, Name VARCHAR (1000) )
--Select the column order from a temp table
IF #TempTable <> 'NULL'
BEGIN
--Verify the temp table exists
IF NOT EXISTS ( SELECT 1
FROM tempdb.sys.columns
WHERE object_id = object_id ('tempdb..' + #TempTable +'') )
BEGIN
RAISERROR ( 'ERROR: Your TempTable does not exist - Please select a valid TempTable.',16,1 )
RETURN
END
SET #SQL = 'INSERT INTO #TempName
SELECT column_id AS ID, Name
FROM tempdb.sys.columns
WHERE object_id = object_id (''tempdb..' + #TempTable +''')
ORDER BY column_id'
EXEC (#SQL)
END
--From a permanent table
IF #PermanentTable <> 'NULL'
BEGIN
--Verify the temp table exists
IF NOT EXISTS ( SELECT 1
FROM syscolumns
WHERE id = ( SELECT id
FROM sysobjects
WHERE Name = '' + #PermanentTable + '' ) )
BEGIN
RAISERROR ( 'ERROR: Your Table does not exist - Please select a valid Table.',16,1 )
RETURN
END
SET #SQL = 'INSERT INTO #TempName
SELECT colorder AS ID, Name
FROM syscolumns
WHERE id = ( SELECT id
FROM sysobjects
WHERE Name = ''' + #PermanentTable + ''' )
ORDER BY colorder'
EXEC (#SQL)
END
--Set the names of the columns
IF #TotalColumns >= 1 BEGIN SET #Column1 = (SELECT Name FROM #TempName WHERE ID = 1) END
IF #TotalColumns >= 2 BEGIN SET #Column2 = (SELECT Name FROM #TempName WHERE ID = 2) END
IF #TotalColumns >= 3 BEGIN SET #Column3 = (SELECT Name FROM #TempName WHERE ID = 3) END
IF #TotalColumns >= 4 BEGIN SET #Column4 = (SELECT Name FROM #TempName WHERE ID = 4) END
IF #TotalColumns >= 5 BEGIN SET #Column5 = (SELECT Name FROM #TempName WHERE ID = 5) END
--Create a select list of only the column names you want
IF Object_id('tempdb..#FinalNames') IS NOT NULL DROP TABLE #FinalNames
CREATE TABLE #FinalNames ( ID INT, Name VARCHAR (1000) )
INSERT #FinalNames
SELECT '1' AS ID, #Column1 AS Name UNION ALL
SELECT '2' AS ID, #Column2 AS Name UNION ALL
SELECT '3' AS ID, #Column3 AS Name UNION ALL
SELECT '4' AS ID, #Column4 AS Name UNION ALL
SELECT '5' AS ID, #Column5 AS Name
--Comma Delimite the names to insert into a select statement. Bracket the names in case there are spaces
SELECT #ColumnNamesAll = COALESCE(#ColumnNamesAll + '], [' ,'[') + Name
FROM #FinalNames
WHERE Name IS NOT NULL
ORDER BY ID
--Add an extra bracket at the end to complete the string
SELECT #ColumnNamesAll = #ColumnNamesAll + ']'
--Tell the user if they selected to many columns
IF ( #TotalColumns > 5 AND EXISTS (SELECT 1 FROM #FinalNames WHERE Name IS NOT NULL) )
BEGIN
SELECT 'This script has been designed for up to 5 columns' AS ERROR
UNION ALL
SELECT 'Only the first 5 columns have been selected' AS ERROR
END
IF Object_id('tempdb..#FinalNames') IS NOT NULL DROP TABLE ##OutputTable
--Select results using only the Columns you wanted
IF #TempTable <> 'NULL'
BEGIN
SET #SQL = 'SELECT ' + #ColumnNamesAll + '
INTO ##OutputTable
FROM ' + #TempTable + '
ORDER BY 1'
EXEC (#SQL)
END
IF #PermanentTable <> 'NULL'
BEGIN
SET #SQL = 'SELECT ' + #ColumnNamesAll + '
INTO ##OutputTable
FROM ' + #PermanentTable + '
ORDER BY 1'
EXEC (#SQL)
END
SELECT *
FROM ##OutputTable
SET NOCOUNT OFF
SQL doesn't understand the order of columns. You need to know the column names to get them.
You can look into querying the information_schema to get the column names. For example:
SELECT column_name
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'tbl_name'
ORDER BY ordinal_position
LIMIT 2;
You can query the sysobject of the table to find out the first two column then dynamically generate the SQL statement you need.
If you want a permant object that you can query over and over again make a view for each table that only returns the first 2 columns. You can name the columns Column1 and Column2 or use the existing names.
If you want to return the first two columns from any table without any preprocessing steps create a stored procedure that queries the system information and executes a dynamic query that return the first two columns from the table.
Or do I have to go the long way around and find out the column names first? How would I do that?
It's pretty easy to do manually.
Just run this first
select * from tbl where 1=0
This statement works on all major DBMS without needing any system catalogs.
That gives you all the column names, then all you need to do is type the first two
select colname1, colnum2 from tbl