How to get column name of particular value in sql server 2008 - sql-server

I want to get column name of particular value. I have table CurrentReport having unique id from which i can get particular row now from the values of that row i want to get the name of columns that i need to update .

I think you want a list of column names that match a particular value.
To do that you can create a XML column in a cross apply for each row and the use nodes() in a second cross apply to shred on the elements that has the value you are looking for.
SQL Fiddle
MS SQL Server 2014 Schema Setup:
create table dbo.CurrentReport
(
ID int primary key,
Col1 varchar(10),
Col2 varchar(10),
Col3 varchar(10)
);
go
insert into dbo.CurrentReport(ID, Col1, Col2, Col3) values(1, 'Value1', 'Value2', 'Value3');
insert into dbo.CurrentReport(ID, Col1, Col2, Col3) values(2, 'Value2', 'Value2', 'Value2');
insert into dbo.CurrentReport(ID, Col1, Col2, Col3) values(3, 'Value3', 'Value3', 'Value3');
Query 1:
-- Value to look for
declare #Value varchar(10) = 'Value2';
select C.ID,
-- Get element name from XML
V.X.value('local-name(.)', 'sysname') as ColumnName
from dbo.CurrentReport as C
cross apply (
-- Build XML for each row
select C.*
for xml path(''), type
) as X(X)
-- Get the nodes where Value = #Value
cross apply X.X.nodes('*[text() = sql:variable("#Value")]') as V(X);
Results:
| ID | ColumnName |
|----|------------|
| 1 | Col2 |
| 2 | Col1 |
| 2 | Col2 |
| 2 | Col3 |

Related

Parsing of String in sql

I have data coming as
**Column**
A/B(D)C
Need output as
Column1 Column2 Column3 Column4
A B D C
Tried to use String Split where i can split only one delimiter which is not as expected
Please try the following solution.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (ID INT IDENTITY PRIMARY KEY, tokens VARCHAR(100));
INSERT #tbl (tokens) VALUES
('A/B(D)C'),
('Miami/Orlando(Denver)Hollywood');
-- DDL and sample data population, start
SELECT t.*
, col1 = PARSENAME(c,4)
, col2 = PARSENAME(c,3)
, col3 = PARSENAME(c,2)
, col4 = PARSENAME(c,1)
FROM #tbl AS t
CROSS APPLY (VALUES (REPLACE(REPLACE(REPLACE(tokens,'/','.'),'(','.'),')','.'))) AS t1(c);
-- SQL Server 2017 onwards
--CROSS APPLY (VALUES (TRANSLATE(tokens,'/()','...'))) AS t1(c);
Output
ID
tokens
col1
col2
col3
col4
1
A/B(D)C
A
B
D
C
2
Miami/Orlando(Denver)Hollywood
Miami
Orlando
Denver
Hollywood

merging and transposing tables

I have sample data set as follows,
| Customer | |Detail | |DataValues |
|----------| |-------| |-----------|
| ID | |ID | |CustomerID |
| Name | |Name | |DetailID |
|Values |
| Customer | |Detail | |DataValues |
|----------| |---------| |-----------|
| 1 | Jack | | 1 | sex | | 1 | 1 | M |
| 2 | Anne | | 2 | age | | 1 | 2 | 30|
| 2 | 1 | F |
| 2 | 2 | 28|
and my desired outcome is below,
Name
Sex
Age
Jack
M
30
Anne
F
28
I have failed to come up with a correct SQL Query that returns anything.
Thanks in advance.
select Customers.Name, Details.Name, DataValues.Value from Customers
inner join DataValues on DataValues.CustomersID = Customers.ID
inner join Details on DataValues.DetailsID = Details.ID
The static way, assuming you know you want exactly Sex and Age:
WITH cte AS
(
SELECT c.Name, Type = d.Name, dv.[Values]
FROM dbo.DataValues AS dv
INNER JOIN dbo.Detail AS d
ON dv.DetailID = d.ID
INNER JOIN dbo.Customer AS c
ON dv.CustomerID = c.ID
WHERE d.Name IN (N'Sex',N'Age')
)
SELECT Name, Sex, Age
FROM cte
PIVOT (MAX([Values]) FOR [Type] IN ([Sex],[Age])) AS p;
If you need to derive the query based on all of the possible attributes, then you'll need to use dynamic SQL. Here's one way:
DECLARE #in nvarchar(max),
#piv nvarchar(max),
#sql nvarchar(max);
SELECT #in = STRING_AGG(N'N' + QUOTENAME(Name, char(39)), ','),
#piv = STRING_AGG(QUOTENAME(Name), ',')
FROM (SELECT Name FROM dbo.Detail GROUP BY Name) AS src;
SET #sql = N'WITH cte AS
(
SELECT c.Name, Type = d.Name, dv.[Values]
FROM dbo.DataValues AS dv
INNER JOIN dbo.Detail AS d
ON dv.DetailID = d.ID
INNER JOIN dbo.Customer AS c
ON dv.CustomerID = c.ID
WHERE d.Name IN (' + #in + N')
)
SELECT Name, ' + #piv + N'
FROM cte
PIVOT (MAX([Values]) FOR [Type] IN (' + #piv + N')) AS p;';
EXECUTE sys.sp_executesql #sql;
Working examples in this fiddle.
There's a lot to unpack here. Let's start with how to present demo data:
If you provide the DDL and DML for your data it makes it much easier for folks to work with:
DECLARE #Customer TABLE (ID INT, Name NVARCHAR(100))
DECLARE #Detail TABLE (ID INT, Name NVARCHAR(20))
DECLARE #DataValues TABLE (CustomerID INT, DetailID INT, [Values] NVARCHAR(20))
INSERT INTO #Customer (ID, Name) VALUES
(1, 'Jack'),(2, 'Anne')
INSERT INTO #Detail (ID, Name) VALUES
(1, 'Sex'),(2, 'Age')
INSERT INTO #DataValues (CustomerID, DetailID, [Values]) VALUES
(1, 1, 'M'),(1, 2, '30'),(2, 1, 'F'),(2, 2, '28')
This sets up your tables (as variables) and populates them with the demo data.
Next let's talk about the horrible schema here.
You should always to try avoid reserved words as column names too. Values is a keyword.
This should probably be a single customers table:
DECLARE #Genders TABLE (ID INT IDENTITY, Name NVARCHAR(20))
DECLARE #Customer1 TABLE (CustomerID INT IDENTITY, Name NVARCHAR(100), BirthDate DATETIME, GenderID INT NULL, Age AS (DATEDIFF(YEAR, BirthDate, CURRENT_TIMESTAMP)))
Notice I used BirthDate instead of Age. This is because a persons age will change over time, but their birth date will not. Attributes that are calculated based on another attribute shouldn't be stored (but if you want you can used a calculated column, as we are here). You'll also note that instead of explicitly defining gender in the customers table we instead will reference it by Gender ID. This is a lookup table.
If you had used a normalized schema your query would then look like:
/* Demo Data */
DECLARE #Genders TABLE (ID INT IDENTITY, Name NVARCHAR(20));
INSERT INTO #Genders (Name) VALUES
('Male'),('Female'),('Non-Binary');
DECLARE #Customer1 TABLE (CustomerID INT IDENTITY, Name NVARCHAR(100), BirthDate DATETIME, GenderID INT NULL, Age AS (DATEDIFF(YEAR, BirthDate, CURRENT_TIMESTAMP)));
INSERT INTO #Customer1 (Name, BirthDate, GenderID) VALUES
('Jack', '2000-11-03', 1),('Anne', '2000-11-01', 2),('Chris', '2001-05-13', NULL);
/* Query */
SELECT *
FROM #Customer1 c
LEFT OUTER JOIN #Genders g
ON c.GenderID = g.ID;
Now on to how to get the data you want from the structure you have. Anyway you do this is going to be acrobatic because we have to work against the schema.
/* Demo Data */
DECLARE #Customer TABLE (ID INT, Name NVARCHAR(100));
DECLARE #Detail TABLE (ID INT, Name NVARCHAR(20));
DECLARE #DataValues TABLE (CustomerID INT, DetailID INT, [Values] NVARCHAR(20));
INSERT INTO #Customer (ID, Name) VALUES
(1, 'Jack'),(2, 'Anne');
INSERT INTO #Detail (ID, Name) VALUES
(1, 'Sex'),(2, 'Age');
INSERT INTO #DataValues (CustomerID, DetailID, [Values]) VALUES
(1, 1, 'M'),(1, 2, '30'),(2, 1, 'F'),(2, 2, '28');
/* Query */
SELECT *
FROM (
SELECT d.Name AS DetailName, c.Name AS CustomerName, DV.[Values]
FROM #DataValues dv
INNER JOIN #Detail d
ON dv.DetailID = d.ID
INNER JOIN #Customer c
ON dv.CustomerID = c.ID
) a
PIVOT (
MAX([Values]) FOR DetailName IN (Sex,Age)
) p;
CustomerName Sex Age
-----------------------
Anne F 28
Jack M 30

Suggestions on T-SQL query [duplicate]

Assuming I have a table containing the following information:
FK | Field1 | Field2
=====================
3 | ABC | *NULL*
3 | *NULL* | DEF
is there a way I can perform a select on the table to get the following
FK | Field1 | Field2
=====================
3 | ABC | DEF
Thanks
Edit: Fix field2 name for clarity
Aggregate functions may help you out here. Aggregate functions ignore NULLs (at least that's true on SQL Server, Oracle, and Jet/Access), so you could use a query like this (tested on SQL Server Express 2008 R2):
SELECT
FK,
MAX(Field1) AS Field1,
MAX(Field2) AS Field2
FROM
table1
GROUP BY
FK;
I used MAX, but any aggregate which picks one value from among the GROUP BY rows should work.
Test data:
CREATE TABLE table1 (FK int, Field1 varchar(10), Field2 varchar(10));
INSERT INTO table1 VALUES (3, 'ABC', NULL);
INSERT INTO table1 VALUES (3, NULL, 'DEF');
INSERT INTO table1 VALUES (4, 'GHI', NULL);
INSERT INTO table1 VALUES (4, 'JKL', 'MNO');
INSERT INTO table1 VALUES (4, NULL, 'PQR');
Results:
FK Field1 Field2
-- ------ ------
3 ABC DEF
4 JKL PQR
There are a few ways depending on some data rules that you have not included, but here is one way using what you gave.
SELECT
t1.Field1,
t2.Field2
FROM Table1 t1
LEFT JOIN Table1 t2 ON t1.FK = t2.FK AND t2.Field1 IS NULL
Another way:
SELECT
t1.Field1,
(SELECT Field2 FROM Table2 t2 WHERE t2.FK = t1.FK AND Field1 IS NULL) AS Field2
FROM Table1 t1
There might be neater methods, but the following could be one approach:
SELECT t.fk,
(
SELECT t1.Field1
FROM `table` t1
WHERE t1.fk = t.fk AND t1.Field1 IS NOT NULL
LIMIT 1
) Field1,
(
SELECT t2.Field2
FROM `table` t2
WHERE t2.fk = t.fk AND t2.Field2 IS NOT NULL
LIMIT 1
) Field2
FROM `table` t
WHERE t.fk = 3
GROUP BY t.fk;
Test Case:
CREATE TABLE `table` (fk int, Field1 varchar(10), Field2 varchar(10));
INSERT INTO `table` VALUES (3, 'ABC', NULL);
INSERT INTO `table` VALUES (3, NULL, 'DEF');
INSERT INTO `table` VALUES (4, 'GHI', NULL);
INSERT INTO `table` VALUES (4, NULL, 'JKL');
INSERT INTO `table` VALUES (5, NULL, 'MNO');
Result:
+------+--------+--------+
| fk | Field1 | Field2 |
+------+--------+--------+
| 3 | ABC | DEF |
+------+--------+--------+
1 row in set (0.01 sec)
Running the same query without the WHERE t.fk = 3 clause, it would return the following result-set:
+------+--------+--------+
| fk | Field1 | Field2 |
+------+--------+--------+
| 3 | ABC | DEF |
| 4 | GHI | JKL |
| 5 | NULL | MNO |
+------+--------+--------+
3 rows in set (0.01 sec)
I had a similar problem. The difference was that I needed far more control over what I was returning so I ended up with an simple clear but rather long query. Here is a simplified version of it based on your example.
select main.id, Field1_Q.Field1, Field2_Q.Field2
from
(
select distinct id
from Table1
)as main
left outer join (
select id, max(Field1)
from Table1
where Field1 is not null
group by id
) as Field1_Q on main.id = Field1_Q.id
left outer join (
select id, max(Field2)
from Table1
where Field2 is not null
group by id
) as Field2_Q on main.id = Field2_Q.id
;
The trick here is that the first select 'main' selects the rows to display. Then you have one select per field. What is being joined on should be all of the same values returned by the 'main' query.
Be warned, those other queries need to return only one row per id or you will be ignoring data
if one row has value in field1 column and other rows have null value then this Query might work.
SELECT
FK,
MAX(Field1) as Field1,
MAX(Field2) as Field2
FROM
(
select FK,ISNULL(Field1,'') as Field1,ISNULL(Field2,'') as Field2 from table1
)
tbl
GROUP BY FK
My case is I have a table like this
---------------------------------------------
|company_name|company_ID|CA | WA |
---------------------------------------------
|Costco | 1 |NULL | 2 |
---------------------------------------------
|Costco | 1 |3 |Null |
---------------------------------------------
And I want it to be like below:
---------------------------------------------
|company_name|company_ID|CA | WA |
---------------------------------------------
|Costco | 1 |3 | 2 |
---------------------------------------------
Most code is almost the same:
SELECT
FK,
MAX(CA) AS CA,
MAX(WA) AS WA
FROM
table1
GROUP BY company_name,company_ID
The only difference is the group by, if you put two column names into it, you can group them in pairs.
SELECT Q.FK
,ISNULL(T1.Field1, T2.Field2) AS Field
FROM (SELECT FK FROM Table1
UNION
SELECT FK FROM Table2) AS Q
LEFT JOIN Table1 AS T1 ON T1.FK = Q.FK
LEFT JOIN Table2 AS T2 ON T2.FK = Q.FK
If there is one table, write Table1 instead of Table2

Convert column to rows in SQL Server

I have a scenario where I need to convert column to rows. I have two tables table1 and table2 with the following structure
Table1:
Col11 Col12 Col13
-------------------------
200 text 55
Table2:
Col1 Col2
--------------------
Col11
Col12
Col13
In need the following result from the above two tables
Col1 Col2
--------------------
Col11 200
Col12 text
Col13 55
Is it possible to do this by using temp tables ?
You can do it using UNION ALL:
SELECT 'Col1' AS Col1, Col1 AS Col2
FROM mytable
UNION ALL
SELECT 'Col2', Col2
FROM mytable
UNION ALL
SELECT 'Col3', Col3
FROM mytable
Table2 doesn't seem to play any role in producing the required result set. So it is left out in the above query.
you can use cross apply or UNPIVOT to get
select
coll,colvalue
from PivotColToRow
cross apply
(
select 'col1', col1 union all
select 'col2', col2 union all
select 'col3', col3
) c (Coll, colvalue);
Using UNPIVOT
select col,colvalue
from PivotColToRow
unpivot
(
colvalue
for col in (col1, col2, col3)
) unpiv;
try this

SQL - Add id to all rows

Let's assume my table is the following:
id | name | country
--------------------
| John | USA
| Mary | USA
| Mike | USA
Someone can help me with a script that can add id's to all names?
Thanks
-- Create a temporary table for the example.
CREATE TABLE #People(Id int, Name nvarchar(10), Country nvarchar(10))
-- Insert data, leaving the Id column NULL.
INSERT INTO #People(Name, Country) SELECT
'John', 'USA' UNION ALL SELECT
'Mary', 'USA' UNION ALL SELECT
'Mike', 'USA';
-- 1. Use Row_Number() to generate an Id.
-- 2. Wrap the query in a common table expression (CTE), which is like an inline view.
-- 3. If the CTE references a single table, we can update the CTE to affect the underlying table.
WITH PeopleCte AS (
SELECT
Id,
Row_Number() OVER (ORDER BY (SELECT NULL)) AS NewId
FROM
#People
)
UPDATE PeopleCte SET Id = NewId
SELECT * FROM #People
DROP TABLE #People
try this
update table set a.id=b.newid from table a,(select row_number() over (order by (select null)) newid,name from #temp) b
make changes like ordering as needed

Resources