Trying to format SQL query results - sql

Found this query here on Stack Overflow which I found very helpful to pull all table names and corresponding columns from a Microsoft SQL Server Enterprise Edition (64-bit) 10.50.4286 SP2 database.
SELECT o.Name, c.Name
FROM sys.columns c
JOIN sys.objects o ON o.object_id = c.object_id
WHERE o.type = 'U'
ORDER BY o.Name, c.Name
It produces a table with two columns like this, each row has the table name in column 01 and the corressponding columns in column 02:
What I really want however is something like this, one column for each table name and the tables columns listed below it like this:
I've already started doing this manually in Excel, but with over 5000 rows returned it would be really nice if there was a way to format the results in the query itself to look like this. Thanks in advance!

As everyone is telling you, this is an un-SQL-y thing to do. Your resultset will have an arbitrary number of columns (equal to the number of user tables in your database, which could be huge). Since the resultset must be rectangular, it will have as many rows as the maximum number of columns in any of your tables, so many of the values will be NULL.
That said, a straightforward dynamic PIVOT gets you what you want:
DECLARE #columns nvarchar(max);
DECLARE #sql nvarchar(max);
SET #columns = STUFF ( (
SELECT '],[' + t.name
FROM sys.tables t
WHERE t.type = 'U'
FOR XML PATH('') ), 1, 2, '')
+ ']';
SET #sql = '
SELECT ' + #columns + '
FROM
(
SELECT t.Name tName
, c.Name cName
, ROW_NUMBER() OVER (PARTITION BY t.Name ORDER BY c.Name) rn
FROM sys.columns c
JOIN sys.tables t ON t.object_id = c.object_id
WHERE t.type = ''U''
) raw
PIVOT (MAX(cName) FOR tName IN ( ' + #columns + ' ))
AS pvt;
';
EXECUTE(#sql);
This is what it produces on my master database:
spt_fallback_db spt_fallback_dev spt_fallback_usg spt_monitor MSreplication_options
------------------- ------------------- ------------------- --------------- ----------------------
dbid high dbid connections install_failures
name low lstart cpu_busy major_version
status name segmap idle minor_version
version phyname sizepg io_busy optname
xdttm_ins status vstart lastrun revision
xdttm_last_ins_upd xdttm_ins xdttm_ins pack_errors value
xfallback_dbid xdttm_last_ins_upd xdttm_last_ins_upd pack_received NULL
xserver_name xfallback_drive xfallback_vstart pack_sent NULL
NULL xfallback_low xserver_name total_errors NULL
NULL xserver_name NULL total_read NULL
NULL NULL NULL total_write NULL
(11 row(s) affected)

It might be easiest to do for example something like this:
Build a comma separated list using for XML path, for example like this.
Then copy that result to excel and use data to columns to create separate columns from the items
Use copy + paste special -> transpose to turn rows into columns

Related

Get count and list of unique values from table without listing each column using SQL in QGIS

Based on questions like SQL to find the number of distinct values in a column and https://gis.stackexchange.com/questions/330932/get-line-length-using-sql-in-qgis
I see we can get a count and list of unique values using SQL but I can't see anything where we can do this without knowing the name of the field.
Is it possible in SQL for QGIS which only allows these commands? I found this option for another flavor -https://dataedo.com/kb/query/sql-server/list-table-columns-in-database
In Mapbasic I have used the following but would like to do this in SQL...
'Get Column Name list
dim x as integer
dim sColName as string
dim aColName as Alias
For x=1 to TableInfo(temptable, TAB_INFO_NCOLS)
sColName = ColumnInfo(temptable, "col"+str$(x), COL_INFO_NAME)
if (sColName not in ("GID","GID_New")) then
aColName = sColName
Select aColName, count(*) from temptable group by aColName into "g_"+sColName
Browse * from "g_"+sColName
Export "g_"+sColName Into WFolder+RSelection.col2+"_"+sColName+".csv" Type "ASCII" Delimiter "," CharSet "WindowsLatin1" Titles
End If
Next
I guess in SQL we would use http://www.sqlservertutorial.net/sql-server-basics/sql-server-select-distinct/ but how can I tell it to just use every column in the table without knowing/specifying the name?
UPDATE
If I run
SELECT DISTINCT * FROM Drainage_Lines_Clip;
I get
But I need something like the following without having to specify the column name. Ref
It should look like this extract from running Unique on a google sheet of the data (except with counts)
So this answer is based upon dynamic SQL. You'll get people saying 'don't use it it's dangerous', but they're the kind of people that think the best access to a system for users is none.. Anyway. Be aware of the security risks with SQL injection when using dynamic SQL. I'll leave that part up to you..
The below goes off to the sys.columns table and grabs all of the column names in the table, then a SQL statement is constructed to count all of the values in each column in your target table.
DECLARE #ReturnVar NVARCHAR(MAX);
SELECT #ReturnVar = COALESCE(#ReturnVar + ' UNION ALL ', '') + 'SELECT ''' + c.[name] + ''' [ColumnName], CAST(' + c.[name] + ' AS VARCHAR(MAX)) [ColumnValue], CAST(COUNT(1) AS VARCHAR(MAX)) [Count] FROM dbo.Admissions GROUP BY CAST(' + c.[name] + ' AS VARCHAR(MAX))'
FROM sys.columns c
INNER JOIN sys.objects o ON o.object_id = c.object_id
INNER JOIN sys.schemas s ON s.schema_id = o.schema_id
WHERE o.[name] = 'Drainage_Lines_Clip'
AND s.[name] = 'dbo'
AND c.[name] != 'GID_New';
EXEC sp_executesql #ReturnVar;
I ended up having to use a combination of PyQGIS and SQL to get what's needed.
layer = qgis.utils.iface.activeLayer()
fields=[] # List of fields
Lquery=[] # List of queries to join together with Union All statement
Cquery=[] # Combined Query to use
for field in layer.fields():
if field.name() not in ('GID_New'):
fields.append(field.name())
query = "Select '{0}' as 'Column', {0} as 'Value', count(*) as 'Unique' from {1} group by {0}".format(field.name(), layer.name())
Lquery.append(query)
else:
print (field.name())
# query = "Select {0}, count(*) from {1} group by {0} order by 2 Desc".format(field.name(), layer.name())
for L in Lquery:
Cquery.append(L+' Union All ')
query=''.join(map(str, Fquery))
query=query[:-11]+' Order by Column'
vlayer = QgsVectorLayer( "?query={}".format(query), 'counts_'+layer.name(), "virtual" )
QgsProject.instance().addMapLayer(vlayer)

How do I delete Columns from a table if not another table using SQL?

Let's say
Table1 has columns: Column1 Column2 Column3
Table2 has columns: Column2 Column3 Column4
I want Column1 to be deleted because it's not in Table2.
I am guessing I need to a JOIN and then delete from that. I did some searching and found this article:
How can I get column names from a table in SQL Server?
I tried:
SELECT T.TABLE_NAME AS 'TABLE NAME',
C.COLUMN_NAME AS 'COLUMN NAME'
FROM INFORMATION_SCHEMA.TABLES T
INNER JOIN INFORMATION_SCHEMA.COLUMNS C ON
T.TABLE_NAME=C.TABLE_NAME
WHERE T.TABLE_TYPE='BASE TABLE'
AND T.TABLE_NAME LIKE 'T'
but I can only get the Column names to show for one Table. I tried modifying it with no luck, and of course I need to delete as well. Even if I could get a list of columns that don't match would help. I am no SQL expert but that's as far as I got. Any help would be appreciated. Thanks!
I've made a simple query that checks what column names both tables are containing and then counts the number of occurences of each name. It then shows the columns that appear less than two times i.e. the ones that only appears in one of the two tables.
select name from (
select [object_id], name from sys.all_columns where [object_id] = (select [object_id] from sys.tables where name = 'Table1')
UNION ALL
select [object_id], name from sys.all_columns where [object_id] = (select [object_id] from sys.tables where name = 'Table2')
) o
group by o.name
having count([object_id]) < 2
You can use the data from this table to make a separate "drop column" query.
You need a dynamic query in this case because you build your drop statement while you are running the select statement to get the column name.
declare #column varchar(max)
set #column = (select............)
-- Print #column -- Use this to check if the column name is what you want
declare #sql nvarchar(max)
set #sql = 'alter table Table1 drop column ' + #column
execute (#sql)
Let me know if you have any questions.

How to use the dynamic column name from the table in a where clause

I am trying to get the dynamic column names from the table using the 'INFORMATION_SCHEMA.COLUMNS' Following is the query.
Select COLUMN_NAME into #TempTable
from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = 'MyTable'
Result:
COLUMN_NAME
Person_ID
Person_Name
Person_Address
Wanting to Do:
Select * from MyTable where Person_ID = 1
What can be the ways to use the Person_ID from 1st query to the second query?
You can use dynamic SQL to execute this via the EXEC command.
Build a VARCHAR string for your query based on the dynamic column names you are getting from your first query, then EXEC on the string you have created.
You have not provided enough information on exactly what columns you need in your WHERE clause, or how you determine which ones, but dynamic SQL seems to be what you need here.
if you are trying to do something like this
select * from [table] where [col] =#param
then you can use query like below
declare #query nvarchar(max)
select
#query='select * from '+t.name +
' where '+c.name + ' ='+
case
when c.name ='Person_ID' then '1'
when c.name ='Someother_ID' then '10'
else c.name
end
from sys.tables t join sys.columns c
on c.object_id=t.object_id
and t.name ='MyTable'
exec( #query)

Get all data, but omit Columns that are auto-increment

I'm struggling to create a query that will return all information from a table (like SELECT *), but I would like to omit the column(s) that are auto-incremental.
Reason is, I'm displaying all data (using SELECT *, because I don't always know what columns are available) in a grid-view control, then I open the table up to allow for updates to be carried out. However this also opens up the column(s) that are assigned as auto-incremental for edit and prevents the update query from working.
So far I found the 'sys.columns.is_identity' table which seems it would help in some fashion, I'm just not sure how I could use this with a dynamic SELECT.
It should be noted that the columns are not always known, hence I use SELECT * to retrieve the initial required data.
As you mentioned, only way to do this is using sys.columns and dynamic query
DECLARE #col_list VARCHAR(8000)
SET #col_list = (SELECT ',' + Quotename(c.NAME)
FROM sys.columns c
JOIN sys.objects o
ON c.object_id = o.object_id
WHERE o.NAME = 'table_name'
AND is_identity <> 1
ORDER BY column_id
FOR xml path(''))
SET #col_list = Stuff(#col_list, 1, 1, '')
EXEC('select '+#col_list +' from yourtable')

SQL - Query only the first 25 columns in that table

75 columns in a table - I want to query only the first 25 columns in that table without naming each column name.... can you assist with a SQL query....
I been playing with the following:
Select Table_Name, Count(*) As ColumnCount
From Information_Schema.Columns
Group By Table_Name
Order By Table_Name
Doesn't meet my output........
If a Table has 75 columns, How can I see the first 25 columns without naming each column name? Don't want to delete Columns Only want to see the first 25 columns out of 75 columns in the same table.....TOP is not enable need another work around....
First 25 columns in a table query built into #query and then executed. Substitute correct #target_table value.
DECLARE
#target_table sysname
, #query nvarchar(max)
SET
#target_table = '_dimAreaOverlay'
; with of_interest as
(
SELECT
SS.name AS schemaname
, T.name AS tablename
, SC.name AS columname
FROM
sys.schemas SS
inner join
sys.tables T
ON T.schema_id = SS.schema_id
inner join
sys.columns SC
ON SC.object_id = T.object_id
WHERE
T.name = #target_table
AND SC.column_id < 26
)
, c AS
(
SELECT
STUFF((
SELECT
',' + QUOTENAME(I.columname)
FROM
of_interest I
FOR XML PATH('')), 1,1, '') AS column_list
, OI.tablename
, OI.schemaname
FROM
of_interest OI
GROUP BY
OI.schemaname
, OI.tablename
)
SELECT
#query = 'SELECT '
+ C.column_list
+ ' FROM '
+ QUOTENAME(C.schemaname)
+ '.'
+ QUOTENAME(C.tablename)
FROM C
EXECUTE(#query)
Find the table in Management Studio Object Explorer.
Right click it and choose Script Table As -> Select To -> New Query Editor Window
Delete unwanted columns.