Query a query's column name in SQL Server - sql-server

I want to query in SQL Server a column's name. I know it is possible to get a table's columns from the system table, but unfortunately that's not enough for me.
Example:
I have a table that contains an ID column and a string column. The table's name is test, and it has a testID and a test column.
This query:
select column_name
from information_schema.columns
where table_name = 'teszt'
return the names of the columns of my table. So it returns testID and Test.
What I want is when I use a query like this:
select count(*) as Amount from test
I want a query that can return the column names of my query. So in this specific case it returns the string 'Amount'. I don't know if that is possible.

Not sure if there is an easier way of getting the name of columns with aliases, but one way of doing it is via XML. This query will return one row per column in the inner query:
select T1.res.value('local-name(.)', 'varchar(50)')
from (select cast(
(
select count(*) as Amount from test
for xml raw) as xml
)) q(res)
CROSS APPLY q.res.nodes('/row/#*') as T1(res)

In SQL Server 2012 you have a stored procedure that you can use for exactly this purpose.
sp_describe_first_result_set (Transact-SQL)
SQL Fiddle
MS SQL Server 2012 Schema Setup:
create table test(id int);
Query 1:
exec sp_describe_first_result_set N'select count(*) as Amount from test'
Results:
| IS_HIDDEN | COLUMN_ORDINAL | NAME | IS_NULLABLE | SYSTEM_TYPE_ID | SYSTEM_TYPE_NAME | MAX_LENGTH | PRECISION | SCALE | COLLATION_NAME | USER_TYPE_ID | USER_TYPE_DATABASE | USER_TYPE_SCHEMA | USER_TYPE_NAME | ASSEMBLY_QUALIFIED_TYPE_NAME | XML_COLLECTION_ID | XML_COLLECTION_DATABASE | XML_COLLECTION_SCHEMA | XML_COLLECTION_NAME | IS_XML_DOCUMENT | IS_CASE_SENSITIVE | IS_FIXED_LENGTH_CLR_TYPE | SOURCE_SERVER | SOURCE_DATABASE | SOURCE_SCHEMA | SOURCE_TABLE | SOURCE_COLUMN | IS_IDENTITY_COLUMN | IS_PART_OF_UNIQUE_KEY | IS_UPDATEABLE | IS_COMPUTED_COLUMN | IS_SPARSE_COLUMN_SET | ORDINAL_IN_ORDER_BY_LIST | ORDER_BY_IS_DESCENDING | ORDER_BY_LIST_LENGTH | TDS_TYPE_ID | TDS_LENGTH | TDS_COLLATION_ID | TDS_COLLATION_SORT_ID |
|-----------|----------------|--------|-------------|----------------|------------------|------------|-----------|-------|----------------|--------------|--------------------|------------------|----------------|------------------------------|-------------------|-------------------------|-----------------------|---------------------|-----------------|-------------------|--------------------------|---------------|-----------------|---------------|--------------|---------------|--------------------|-----------------------|---------------|--------------------|----------------------|--------------------------|------------------------|----------------------|-------------|------------|------------------|-----------------------|
| 0 | 1 | Amount | 1 | 56 | int | 4 | 10 | 0 | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) | 0 | 0 | 0 | (null) | (null) | (null) | (null) | (null) | 0 | (null) | 0 | 0 | 0 | (null) | (null) | (null) | 38 | 4 | (null) | (null) |

Maybe you want something like this? :-)
SELECT AMOUNT
FROM
(
SELECT COUNT(*) AS AMOUNT
FROM TEST
)X

Related

TSQL query parser in TSQL

I would like to have something like a procedure that takes a query definition as input and output a set of tables containing the individual elements of the query.
Searching the internet for this yields me numerous results in various programming languages, but not in tsql itself. Is there such a resource around?
An example in order to illustrate what I mean by parser:
Input example (any query, really:)
'select t1.col1,t2.col2
from table1 t1
inner join table2.col2
on t1.t2ref=t2.key'
The output, of course, will be a multitude of data. I mentioned tables, but it could be in any form eg an xml. Here is a VERY SIMPLISTIC and arbitrary example of decomposition for the query above:
tables_used:
+----+-----------+--------+------------+
| id | object_id | name | alias used |
+----+-----------+--------+------------+
| 1 | 43252345 | table1 | t1 |
| 2 | 6542625 | table2 | t2 |
+----+-----------+--------+------------+
columns_used:
+----------+-------------+
| table_id | column name |
+----------+-------------+
| 1 | col1 |
| 1 | t2ref |
| 2 | key |
| 2 | col2 |
+----------+-------------+
joins_used:
+-----+-----+-------+-----------------+
| tb1 | tb2 | type | on |
+-----+-----+-------+-----------------+
| 1 | 2 | inner | t1.t2ref=t2.key |
+-----+-----+-------+-----------------+

Exclude Secondary ID Records from Original SELECT

I'm relatively new to SQL and am running into a lot of issues trying to figure this one out. I've tried using a LEFT JOIN, and dabbled in using functions to get this to work but to no avail.
For every UserID, if there is a NULL value, I need to remove all records of the Product ID for that UserID from my SELECT.
I am using SQL Server 2014.
Example Table
+--------------+-------------+---------------+
| UserID | ProductID | DateTermed |
+--------------+-------------+---------------+
| 578 | 2 | 1/7/2017 |
| 578 | 2 | 1/7/2017 |
| 578 | 1 | 1/15/2017 |
| 578 | 1 | NULL |
| 649 | 1 | 1/9/2017 |
| 649 | 2 | 1/11/2017 |
+--------------+-------------+---------------+
Desired Output
+--------------+-------------+---------------+
| UserID | ProductID | DateTermed |
+--------------+-------------+---------------+
| 578 | 2 | 1/7/2017 |
| 578 | 2 | 1/7/2017 |
| 649 | 1 | 1/9/2017 |
| 649 | 2 | 1/11/2017 |
+--------------+-------------+---------------+
Try the following:
SELECT a.userid, a.productid, a.datetermed
FROM yourtable a
LEFT OUTER JOIN (SELECT userid, productid, datetermed FROM yourtable WHERE
datetermed is null) b
on a.userid = b.userid and a.productid = b.productid
WHERE b.userid is not null
This will left outer join all records with a null date to their corresponding UserID and ProductID records. If you only take records that don't have an associated UserID and ProductID in the joined table, you should only be left with records that don't have a null date.
You can use this WHERE condition:
SELECT
UserID,ProducID,DateTermed
FROM
[YourTableName]
WHERE
(CONVERT(VARCHAR,UserId)+
CONVERT(VARCHAR,ProductID) NOT IN (
select CONVERT(VARCHAR,UserId)+ CONVERT(VARCHAR,ProductID)
from
[YourTableName]
where DateTermed is null)
)
When you concatenate the UserId and the ProductId get a unique value for each pair, then you can use them as a "key" to exclude the "pairs" that have the null value in the DateTermed field.
Hope this help.

Combine tables in select based on criteria in a column SQLServer

I have two tables (each with about 20 columns), none of the column names match up but some of the values in 1 column match the values in another (see below).
I want to get a the combination of the 2 tables on certain columns based on True/False values in a column on the primary table.
I am doing all of this using the SQLServer Third Party JDBC Drivers in Oracle's SQL Developer (I am not sure if or how that might have an effect on my syntax).
I am sure that this is simple, but I cannot find any examples that do this and I am just too new to SQL to wrap my head around it.
CREATE TABLE [dbo].[TableA] (
[colA1] VARCHAR (10) NULL,
[colA2] VARCHAR (10) NULL,
[colA3] VARCHAR (10) NULL,
[colA4] VARCHAR (10) NULL,
[colA5] VARCHAR (10) NULL,
[colA6] INT NULL,
[colKey] INT NOT NULL,
CONSTRAINT [PK_TableA] PRIMARY KEY CLUSTERED ([colKey] ASC)
);
CREATE TABLE [dbo].[TableB] (
[colB1] VARCHAR (10) NULL,
[colB2] VARCHAR (10) NULL,
[colB3] VARCHAR (10) NULL,
[colB4] INT NULL,
[colKey] INT NOT NULL,
PRIMARY KEY CLUSTERED ([colKey] ASC)
);
INSERT INTO TableA(colKey,colA1,colA2,colA3,colA4,colA5,colA6) VALUES (1,'AC1-1','AC2-1','AC3-1',NULL,'FALSE',2016);
INSERT INTO TableA(colKey,colA1,colA2,colA3,colA4,colA5,colA6) VALUES (2,'AC1-2','AC2-2','AC3-2',NULL,'FALSE',2016);
INSERT INTO TableA(colKey,colA1,colA2,colA3,colA4,colA5,colA6) VALUES (3,'AC1-3',NULL,NULL,'AC4-3','TRUE',2016);
INSERT INTO TableA(colKey,colA1,colA2,colA3,colA4,colA5,colA6) VALUES (4,'AC1-4',NULL,NULL,'AC4-4','TRUE',2016);
INSERT INTO TableA(colKey,colA1,colA2,colA3,colA4,colA5,colA6) VALUES (5,'AC1-5','AC2-5','AC3-5',NULL,'FALSE',2015);
INSERT INTO TableA(colKey,colA1,colA2,colA3,colA4,colA5,colA6) VALUES (6,'AC1-6','AC2-6','AC3-6',NULL,'FALSE',2015);
INSERT INTO TableA(colKey,colA1,colA2,colA3,colA4,colA5,colA6) VALUES (7,'AC1-7',NULL,NULL,'AC4-7','TRUE',2015);
INSERT INTO TableA(colKey,colA1,colA2,colA3,colA4,colA5,colA6) VALUES (8,'AC1-8',NULL,NULL,'AC4-8','TRUE',2015);
INSERT INTO TableA(colKey,colA1,colA2,colA3,colA4,colA5,colA6) VALUES (9,'AC1-9',NULL,NULL,'AC4-9','TRUE',2016);
INSERT INTO TableB(colKey,colB1,colB2,colB3,colB4) VALUES (1,'AC4-3','BC2-1','BC3-1',2015);
INSERT INTO TableB(colKey,colB1,colB2,colB3,colB4) VALUES (2,'AC4-4','BC2-2','BC3-2',2015);
INSERT INTO TableB(colKey,colB1,colB2,colB3,colB4) VALUES (3,'AC4-4','BC2-3','BC3-3',2016);
INSERT INTO TableB(colKey,colB1,colB2,colB3,colB4) VALUES (4,'AC4-3','BC2-4','BC3-4',2016);
INSERT INTO TableB(colKey,colB1,colB2,colB3,colB4) VALUES (5,'AC4-7','BC2-5','BC3-5',2015);
INSERT INTO TableB(colKey,colB1,colB2,colB3,colB4) VALUES (6,'AC4-8','BC2-6','BC3-6',2015);
TableA
+-------+--------+--------+--------+-------+-------+
| colA1 | colA2 | colA3 | colA4 | colA5 | colA6 |
+-------+--------+--------+--------+-------+-------+
| AC1-1 | AC2-1 | AC3-1 | (Null) | FALSE | 2016 |
| AC1-2 | AC2-2 | AC3-2 | (Null) | FALSE | 2016 |
| AC1-3 | (Null) | (Null) | AC4-3 | TRUE | 2016 |
| AC1-4 | (Null) | (Null) | AC4-4 | TRUE | 2016 |
| AC1-5 | AC2-5 | AC3-5 | (Null) | FALSE | 2015 |
| AC1-6 | AC2-6 | AC3-6 | (Null) | FALSE | 2015 |
| AC1-7 | (Null) | (Null) | AC4-7 | TRUE | 2015 |
| AC1-8 | (Null) | (Null) | AC4-8 | TRUE | 2015 |
| AC1-9 | (Null) | (Null) | AC4-9 | TRUE | 2016 |
+-------+--------+--------+--------+-------+-------+
TableB
+-------+-------+-------+-------+
| colB1 | colB2 | colB3 | colB4 |
+-------+-------+-------+-------+
| AC4-3 | BC2-1 | BC3-1 | 2015 |
| AC4-4 | BC2-2 | BC3-2 | 2015 |
| AC4-4 | BC2-3 | BC3-3 | 2016 |
| AC4-3 | BC2-4 | BC3-4 | 2016 |
+-------+-------+-------+-------+
Results Table
+-------+--------+-------+-------------------------+-------------------------+
| colA1 | colA4 | colA5 | combined(colA2 & colB2) | combined(colA3 & colB3) |
+-------+--------+-------+-------------------------+-------------------------+
| AC1-1 | (null) | FALSE | AC2-1 | AC3-1 |
| AC1-2 | (null) | FALSE | AC2-2 | AC3-2 |
| AC1-3 | AC4-3 | TRUE | BC2-1 | BC3-1 |
| AC1-4 | AC4-4 | TRUE | BC2-2 | BC3-2 |
| AC1-9 | AC4-9 | TRUE | (null) | (null) |
+-------+--------+-------+-------------------------+-------------------------+
So I think I need some kind of SELECT like this:
SELECT colA1, colA5,
IF colA5 = True
THEN colB2, colB3, etc.
ELSE colA2, ColA3, etc.
FROM tableB, tableA
WHERE colA1 = colB1 AND colB4 = 2016 AND colA6 = 2016
I have tried this:
SELECT A.colA1
,A.colA4
,A.colA5
,CASE
WHEN A.colA5 = TRUE
THEN B.colB2
ELSE A.colA2
END AS 'combined(colA2 & colB2)'
,CASE
WHEN A.colA5 = TRUE
THEN B.colB3
ELSE A.colA4
END AS 'combined(colA3 & colB3)'
,
FROM TableA A
,TableB B
WHERE A.colA6 = '2016'
AND B.colB4 = '2016'
AND (
A.colA4 = B.colB1
OR A.colA4 IS NULL
)
what I get is this:
+-------+-------+-------+-------------------------+-------------------------+
| colA1 | colA4 | colA5 | combined(colA2 & colB2) | combined(colA3 & colB3) |
+-------+-------+-------+-------------------------+-------------------------+
| AC1-3 | AC4-3 | TRUE | BC2-1 | BC3-1 |
| AC1-4 | AC4-4 | TRUE | BC2-2 | BC3-2 |
+-------+-------+-------+-------------------------+-------------------------+
So I am missing the rows were TableA/colA5 are FALSE. Also, I need 12 of these "combined" columns, is there a way that I can avoid using 12 CASE statements?
After learning about joins and case here is the answer (though apparently I will have to use the 12 CASE statements that I would have preferred to avoid).
SELECT A.colA1
,A.colA4
,A.colA5
,CASE
WHEN A.colA5 = 'TRUE'
THEN B.colB2
ELSE A.colA2
END AS 'combined(colA2 & colB2)'
,CASE
WHEN A.colA5 = 'TRUE'
THEN B.colB3
ELSE A.colA3
END AS 'combined(colA3 & colB3)'
FROM TableA A LEFT JOIN TableB B ON A.colA4 = B.colB1
WHERE (A.colA6 = '2016' and A.colA5 ='FALSE')
or (A.colA6 = '2016' and A.colA5 ='true' and B.colB4 = '2016')
or (A.colA6 = '2016' and A.colA5 ='true' and B.colB4 is null)
;

How to create a cross tab (in crystal) from multiple columns (in sql)

I have 5 columns in SQL that I need to turn into a cross tab in Crystal.
This is what I have:
Key | RELATIONSHIP | DISABLED | LIMITED | RURAL | IMMIGRANT
-----------------------------------------------------------------
1 | Other Dependent | Yes | No | No | No
2 | Victim/Survivor | No | No | No | No
3 | Victim/Survivor | Yes | No | No | No
4 | Child | No | No | No | No
5 | Victim/Survivor | No | No | No | No
6 | Victim/Survivor | No | No | No | No
7 | Child | No | No | No | No
8 | Victim/Survivor | No | Yes | Yes | Yes
9 | Child | No | Yes | Yes | Yes
10 | Child | No | Yes | Yes | Yes
This is what I want the cross tab to look like (Distinct count on Key):
| Victim/Survivor | Child | Other Dependent | Total |
--------------------------------------------------------------
| DISABLED | 1 | 0 | 1 | 2 |
--------------------------------------------------------------
| LIMITED | 1 | 2 | 0 | 3 |
--------------------------------------------------------------
| RURAL | 1 | 2 | 0 | 3 |
--------------------------------------------------------------
| IMMIGRANT | 1 | 2 | 0 | 3 |
--------------------------------------------------------------
| TOTAL | 4 | 6 | 1 | 11 |
--------------------------------------------------------------
I used this formula in Crystal in an effort to combine 4 columns (Field name = {#OTHERDEMO})...
IF {TABLE.DISABLED} = "YES" THEN "DISABLED" ELSE
IF {TABLE.LIMITED} = "YES" THEN "LIMITED" ELSE
IF {TABLE.IMMIGRANT} = "YES" THEN "IMMIGRANT" ELSE
IF {TABLE.RURAL} = "YES" THEN "RURAL"
...then made the cross-tab with #OTHERDEMO as the rows, RELATIONSHIP as the Columns with a distinct count on KEY:
Problem is, once crystal hits the first "Yes" it stops counting thus not categorizing correctly in the cross-tab. So I get a table that counts the DISABILITY first and gives the correct display, then counts the Limited and gives some info, but then dumps everything else.
In the past, I have done mutiple conditional formulas...
IF {TABLE.DISABLED} = "YES" AND {TABLE.RELATIONSHIP} = "Victim/Survivor" THEN {TABLE.KEY} ELSE {#NULL}
(the #null formula is because Crystal, notoriously, gets confused with nulls.)
...then did a distinct count on Key, and finally summed it in the footer.
I am convinced there is another way to do this. Any help/ideas would be greatly appreciated.
If you unpivot those "DEMO" columns into rows it will make the crosstab super easy...
select
u.[Key],
u.[RELATIONSHIP],
u.[DEMO]
from
Table1
unpivot (
[b] for [DEMO] in ([DISABLED], [LIMITED], [RURAL], [IMMIGRANT])
) u
where
u.[b] = 'Yes'
SqlFiddle
or if you were stuck on SQL2000 compatibility level you could manually unpivot the Yes values...
select [Key], [REALTIONSHIP], [DEMO] = cast('DISABLED' as varchar(20))
from Table1
where [DISABLED] = 'Yes'
union
select [Key], [REALTIONSHIP], [DEMO] = cast('LIMITED' as varchar(20))
from Table1
where [LIMITED] = 'Yes'
union
select [Key], [REALTIONSHIP], [DEMO] = cast('RURAL' as varchar(20))
from Table1
where [RURAL] = 'Yes'
union
select [Key], [REALTIONSHIP], [DEMO] = cast('IMMIGRANT' as varchar(20))
from Table1
where [IMMIGRANT] = 'Yes'
For the crosstab, use a count on the Key column (aka row count), [DEMO] on rows, and [RELATIONSHIP] on columns.

T-SQL Merging data

I've imported data from an XML file by using SSIS to SQL Server.
The result what I got in the database is similar to this:
+-------+---------+---------+-------+
| ID | Name | Brand | Price |
+-------+---------+---------+-------+
| 2 | NULL | NULL | 100 |
| NULL | SLX | NULL | NULL |
| NULL | NULL | Blah | NULL |
| NULL | NULL | NULL | 100 |
+-------+---------+---------+-------+
My desired result would be:
+-------+---------+---------+-------+
| ID | Name | Brand | Price |
+-------+---------+---------+-------+
| 2 | SLX | Blah | 100 |
+-------+---------+---------+-------+
Is there a pretty solution to solve this in T-SQL?
I've already tried it with a SELECT MAX(ID) and then a GROUP BY ID, but I'm still stuck with the NULL values. Also I've tried it with MERGE, but also a failure.
Could someone give me a direction where to search further?
You can select MAX on all columns....
SELECT MAX(ID), MAX(NAME), MAX(BRAND), MAX(PRICE)
FROM [TABLE]
Click here for a fiddley fidd fiddle...

Resources