Query column headings data in SQL - sql-server

I need to display column headings that occur in a different table as a list.
Example:
Column headings - Adam, Cory, Jack, Jane, John, Josef, Mary, Timothy, Charlotte, Jessica, Kristal, Clive
Required column headings (contained within another table) - Jack, Jane, John, Mary, Maria, Josef
How would I check if the column headings are equal to any in the "required" list and then display only those?

I recommend you make use of Pivot and Dynamic SQL. Join from your complete names table to the required names table to end up with just the names you need as columns. Format those values to be later used in pivot with dynamic SQL. With pivot you are forced to aggregate something. Look at the Pivot rows to columns without aggregate post for more information. I hard coded 1 as the aggregate value we need to be able to pivot. You can ignore that value and join on name assuming that is your key to other tables to get additional data for each name.
https://learn.microsoft.com/en-us/sql/t-sql/queries/from-using-pivot-and-unpivot?view=sql-server-ver15
https://learn.microsoft.com/en-us/sql/odbc/reference/dynamic-sql?view=sql-server-ver15
Pivot rows to columns without aggregate
declare #PivotColumns nvarchar(max) = ''
create table #required ( name nvarchar(500) )
insert into #required ([name])
select 'Jack' union select 'Jane' union select 'John' union select 'Mary' union select 'Maria' union select 'Josef'
create table #allnames ( name nvarchar(500) )
insert into #allnames ([name])
select 'Adam' union select 'Cory' union select 'Jack' union select 'Jane' union select 'John' union select 'Josef' union select 'Mary' union select 'Timothy' union select 'Charlotte' union select 'Jessica' union select 'Kristal' union select 'Clive' union select 'Maria'
select #PivotColumns = #PivotColumns + QUOTENAME([name]) + ',' from #required
select #PivotColumns = substring(#PivotColumns,1,len(#PivotColumns)-1)
declare #SQL nvarchar(max) = ''
select #SQL = N'
select
*
from (
select
req.*, 1 [Val]
from #allnames as [All]
join #required as Req
on [All].[name] = Req.[name]
) src
pivot
(
max([Val])
FOR [name] in ('+#PivotColumns+')
) piv';
exec sp_executesql #SQL
drop table #required
drop table #allnames

Related

Identify "Character space Character"

I'm needing to identify all records within FirstName that contain values such as A & B or B C
Is there a way I could go about identifying these records? I have this currently, but it doesn't quite get me there:
select * from #temp
WHERE FirstName LIKE '%[a-z] [a-z]%' or
FirstName LIKE '%[a-z] & [a-z]%'
Sample Code:
Create table #temp
(
FirstName varchar(50)
)
insert into #temp
(
FirstName
)
select
'Mary Smith'
union
select
'John'
union
select
'Bob'
union
select
'Bruce'
union
select
'Sally'
union
select
'A & B'
union
select
'B C'
select * from #temp
drop table #temp
If you remove the wildcard character from your like expression (%) it will match your current test data e.g.
select *
from #temp
where FirstName like '[a-z] [a-z]'
or FirstName like '[a-z] & [a-z]';

create a stored procwhich pulls all data from 3 tables in which 2 tables are having same column name and 3rd table having different column name

Need to create a stored procedure which pulls all the data from three different tables in which two tables are having same column name and third table having different column name,
I have tried this,
Create PROCEDURE [dbo].XYZ
#ssn VARCHAR(11)
AS
BEGIN
SELECT *
FROM ([dbo].[TBL_A]
WHERE REPLACE(ssn,'-','') = #ssn
UNION
SELECT *
FROM [dbo].[TBL_B]
WHERE REPLACE(ssn,'-','') = #ssn
UNION
SELECT *
FROM [dbo].[TBL_C]
WHERE (ssn_tin) = #ssn
END
GO
Use a derived query with your union and don't use *.
select x.field1, x.field2
from (
SELECT field1, field2
FROM ([dbo].[TBL_A]
WHERE REPLACE(ssn,'-','') = #ssn
UNION
SELECT field1, field2
FROM [dbo].[TBL_B]
WHERE REPLACE(ssn,'-','') = #ssn
UNION
SELECT field3, field4
FROM [dbo].[TBL_C]
WHERE (ssn_tin) = #ssn
) x

Unpivot dynamic table columns into key value rows

The problem that I need to resolve is data transfer from one table with many dynamic fields into other structured key value table.
The first table comes from a data export from another system, and has the following structure ( it can have any column name and data):
[UserID],[FirstName],[LastName],[Email],[How was your day],[Would you like to receive weekly newsletter],[Confirm that you are 18+] ...
The second table is where I want to put the data, and it has the following structure:
[UserID uniqueidentifier],[QuestionText nvarchar(500)],[Question Answer nvarchar(max)]
I saw many examples showing how to unpivot table, but my problem is that I dont know what columns the Table 1 will have. Can I somehow dynamically unpivot the first table,so no matter what columns it has, it is converted into a key-value structure and import the data into the second table.
I will really appreciate your help with this.
You can't pivot or unpivot in one query without knowing the columns.
What you can do, assuming you have privileges, is query sys.columns to get the field names of your source table then build an unpivot query dynamically.
--Source table
create table MyTable (
id int,
Field1 nvarchar(10),
Field2 nvarchar(10),
Field3 nvarchar(10)
);
insert into MyTable (id, Field1, Field2, Field3) values ( 1, 'aaa', 'bbb', 'ccc' );
insert into MyTable (id, Field1, Field2, Field3) values ( 2, 'eee', 'fff', 'ggg' );
insert into MyTable (id, Field1, Field2, Field3) values ( 3, 'hhh', 'iii', 'jjj' );
--key/value table
create table MyValuesTable (
id int,
[field] sysname,
[value] nvarchar(10)
);
declare #columnString nvarchar(max)
--This recursive CTE examines the source table's columns excluding
--the 'id' column explicitly and builds a string of column names
--like so: '[Field1], [Field2], [Field3]'.
;with columnNames as (
select column_id, name
from sys.columns
where object_id = object_id('MyTable','U')
and name <> 'id'
),
columnString (id, string) as (
select
2, cast('' as nvarchar(max))
union all
select
b.id + 1, b.string + case when b.string = '' then '' else ', ' end + '[' + a.name + ']'
from
columnNames a
join columnString b on b.id = a.column_id
)
select top 1 #columnString = string from columnString order by id desc
--Now I build a query around the column names which unpivots the source and inserts into the key/value table.
declare #sql nvarchar(max)
set #sql = '
insert MyValuestable
select id, field, value
from
(select * from MyTable) b
unpivot
(value for field in (' + #columnString + ')) as unpvt'
--Query's ready to run.
exec (#sql)
select * from MyValuesTable
In case you're getting your source data from a stored procedure, you can use OPENROWSET to get the data into a table, then examine that table's column names. This link shows how to do that part.
https://stackoverflow.com/a/1228165/300242
Final note: If you use a temporary table, remember that you get the column names from tempdb.sys.columns like so:
select column_id, name
from tempdb.sys.columns
where object_id = object_id('tempdb..#MyTable','U')

Selecting multiple rows of date into one row, based on a unque value

I would like to select multiple rows of data into a single row.
The data I am working with has two columns:
loan numbers
names
There is a different row for each name attached to the loan number.
Example:
loan number 1 has 3 different names, therefore the loan number has 3 rows, one for each name.
What I want to do is, take each different name and assign it a new column so I have one unique row per loan number with each different name attached to it in their own column, rather than a row for each name.
Is this something that can be done in the select state using partition?
I dont think you're going to do this with pure SQL. I'd try to use a stored procedure, and something like create temporary table. I think you'd have to dynamically build up a string to get sqlserver to execute, to create the table. Then you can do updates against it, and eventually return the single row using select.
Are you going to attempt to return multiple loans, one in each row (albeit, each with their loan names in differing rows)? Because if loan one had three names and loan two had four names, that's not going to work out in the same table.
How about pack all the names into a pipe-delimited string into column two, and the loan number in column one? A stored proc may still be needed but it'd be a lot easier than creating varying numbers of columns. Then split on the pipe on the client side of the database to get the names out.
You can do this with dynamic pivots, although your column names become the user names, that's not a big deal if you're handling the output in c#; you can just iterate over a field count. One catch would be if you have two users with identical names, they would only show once.
Here's a great SO post on dynamic pivots.
Using this method I came up with the sample code below. (Note the line SET #loanID = 1 - change between 1 and 2 to test outputs)
IF OBJECT_ID('TEMPDB..#LOANS') IS NOT NULL
DROP TABLE #LOANS
CREATE TABLE #LOANS (LOANID INT, USERNAME NVARCHAR(100))
INSERT INTO #LOANS
SELECT 1, 'Neal' UNION ALL
SELECT 1, 'Bob' UNION ALL
SELECT 2, 'Sarah' UNION ALL
SELECT 2, 'John' UNION ALL
SELECT 2, 'Elsa' UNION ALL
SELECT 2, 'Jennifer' UNION ALL
SELECT 2, 'Dave'
DECLARE #cols AS NVARCHAR(MAX), #y AS INT, #sql AS NVARCHAR(MAX), #loanID INT
-- set an id here...
SET #loanID = 1
SET #cols = STUFF(
(SELECT N',' + QUOTENAME(y) AS [text()]
FROM (SELECT DISTINCT USERNAME AS y
FROM #LOANS
WHERE LOANID=#loanID) AS Y
ORDER BY y
FOR XML PATH('')),
1, 1, N'');
SET #sql = N'SELECT *
FROM (SELECT LOANID, USERNAME
FROM #LOANS
WHERE LOANID='+CAST(#loanID AS NVARCHAR)+') AS D
PIVOT(MIN(USERNAME) FOR USERNAME IN(' + #cols + N')) AS P;';
EXEC sp_executesql #sql;
GO
If you had a userID, your results could look like this instead:
IF OBJECT_ID('TEMPDB..#LOANS') IS NOT NULL
DROP TABLE #LOANS
CREATE TABLE #LOANS (LOANID INT, USERNAME NVARCHAR(100), USERID INT)
INSERT INTO #LOANS
SELECT 1, 'Neal', 1 UNION ALL
SELECT 1, 'Bob', 2 UNION ALL
SELECT 2, 'Sarah', 3 UNION ALL
SELECT 2, 'John', 4 UNION ALL
SELECT 2, 'Elsa', 5 UNION ALL
SELECT 2, 'Jennifer', 6 UNION ALL
SELECT 2, 'Dave', 7
DECLARE #cols AS NVARCHAR(MAX), #y AS INT, #sql AS NVARCHAR(MAX), #loanID INT
-- set an id here...
SET #loanID = 1
SET #cols = STUFF(
(SELECT N',' + QUOTENAME(y) AS [text()]
FROM (SELECT DISTINCT USERID AS y
FROM #LOANS
WHERE LOANID=#loanID) AS Y
ORDER BY y
FOR XML PATH('')),
1, 1, N'');
SET #sql = N'SELECT *
FROM (SELECT LOANID, USERNAME, USERID
FROM #LOANS
WHERE LOANID='+CAST(#loanID AS NVARCHAR)+') AS D
PIVOT(MIN(USERNAME) FOR USERID IN(' + #cols + N')) AS P;';
EXEC sp_executesql #sql;
GO

SQL Server PIVOT Column Data

I have a table with data as given below:
DATE Price
---------- ------
31/12/2009 10
31/12/2009 11
31/12/2009 12
30/12/2009 20
30/12/2009 21
30/12/2009 22
29/12/2009 30
29/12/2009 32
29/12/2009 31
I want to convert this data as given below:
31/12/2009 30/12/2009 29/12/2009
---------- ---------- ----------
10 10 10
11 11 11
12 12 12
But the values in the date column is dynamic. So, I dont know how to use this using SQL Server Pivot.
Could you please let me know how to get this data.
Given below is the script to replicate this scenario:
CREATE TABLE TEMP(EffectiveDate DATETIME,Price INT)
INSERT INTO TEMP(EffectiveDate,Price)
SELECT GETDATE(),10
UNION ALL
SELECT GETDATE(),11
UNION ALL
SELECT GETDATE(),12
UNION ALL
SELECT GETDATE()-1,20
UNION ALL
SELECT GETDATE()-1,21
UNION ALL
SELECT GETDATE()-1,22
UNION ALL
SELECT GETDATE()-2,30
UNION ALL
SELECT GETDATE()-2,32
UNION ALL
SELECT GETDATE()-2,31
SELECT CONVERT(VARCHAR,EffectiveDATE,103) AS 'DATE',Price FROM Temp
Thanks in advance,
Mahesh
OK, as I mentioned, your data does not make sense, but maybe this can help.
The only way to create a dynamic pivot, is by creating dynamic sql.
Also, PIVOT requires that you use an Aggregate function (SUM, AVG, COUNT).
Ok, let see if this can help you.
CREATE TABLE #TEMP (EffectiveDate DATETIME,Price INT)
INSERT INTO #TEMP(EffectiveDate,Price)
SELECT GETDATE(),10
UNION ALL
SELECT GETDATE(),11
UNION ALL
SELECT GETDATE(),12
UNION ALL
SELECT GETDATE()-1,20
UNION ALL
SELECT GETDATE()-1,21
UNION ALL
SELECT GETDATE()-1,22
UNION ALL
SELECT GETDATE()-2,30
UNION ALL
SELECT GETDATE()-2,32
UNION ALL
SELECT GETDATE()-2,31
DECLARE #Cols VARCHAR(MAX)
SELECT #cols = COALESCE(#cols + ',[' + colName + ']',
'[' + colName + ']')
FROM (
SELECT DISTINCT
CONVERT(VARCHAR,EffectiveDATE,103) colName
FROM #TEMP
) s
ORDER BY colName DESC
DECLARE #query VARCHAR(MAX)
SET #query = N'SELECT *
FROM
(SELECT CONVERT(VARCHAR,EffectiveDATE,103) AS ''DATE'',Price
FROM #TEMP) p
PIVOT
(
SUM(Price) FOR DATE IN
( '+
#cols +' )
) AS pvt'
EXECUTE(#query)
DROP TABLE #TEMP

Resources