Convert Colums Values Into Row result - sql

Sorry If this is duplicate...
I have this table (Id,Col1,Col2,..,Col3) but I want to have results grouped like this
ID1value group,
Col1Value,
Col2Value,
Col3Value
ID2value group,
ID2Col1Value,
ID2Col2Value,
ID2Col3Value
ID3value group,
ID3Col1Value,
ID3Col2Value,
ID3Col3Value
How to do it?
I have tried PIVOT but I think this does not return good result

It sounds like you want UNPIVOT as opposed to PIVOT:
DECLARE #T TABLE (ID INT, Col1 VARCHAR(15), Col2 VARCHAR(15), Col3 VARCHAR(15))
INSERT #T (ID, Col1, Col2, Col3)
VALUES
(1, 'ID1Col1Value', 'ID1Col2Value', 'ID1Col3Value'),
(2, 'ID2Col1Value', 'ID2Col2Value', 'ID2Col3Value'),
(3, 'ID3Col1Value', 'ID3Col2Value', 'ID3Col3Value');
SELECT upvt.ID,
upvt.Value
FROM #T
UNPIVOT
( Value
FOR [Group] IN ([Col1], [Col2], [Col3])
) AS upvt;
Giving:
+----+--------------+
| ID | Value |
+----+--------------+
| 1 | ID1Col1Value |
| 1 | ID1Col2Value |
| 1 | ID1Col3Value |
| 2 | ID2Col1Value |
| 2 | ID2Col2Value |
| 2 | ID2Col3Value |
| 3 | ID3Col1Value |
| 3 | ID3Col2Value |
| 3 | ID3Col3Value |
+----+--------------+

Related

How to use a column as a key to pivot columns in SQL

I am trying to pivot a table and aggregate some sub-categories. However, when aggregating, the sub-categories aren't joining properly.
Example Table
| category | categorySub |
|----------|-------------|
| cat-1 | sub-1 |
| cat-1 | sub-2 |
| cat-1 | sub-3 |
| cat-2 | sub-4 |
| cat-2 | sub-5 |
Actual Output
| category | categorySub |
|----------|-------------------------------------------|
| cat-1 | ["sub-1","sub-2","sub-3","sub-4","sub-5"] |
| cat-2 | ["sub-1","sub-2","sub-3","sub-4","sub-5"] |
Desired Output
| category | categorySub |
|----------|---------------------------|
| cat-1 | ["sub-1","sub-2","sub-3"] |
| cat-2 | ["sub-4","sub-5"] |
Query
select
[categoryMain] = [category],
[categorySub] = '["' + (select string_agg(categorySub, '","') from someTable where [categoryMain] = [category]) + '"]'
from someTable
group by [category]
How can I reference [category] or its alias to pare down the string aggregation?
You can use that in STRING_AGG itself
DECLARE #T Table(
cat Varchar(max),
SUB varchar(max))
Insert into #T Values ('cat-1','sub-1')
Insert into #T Values ('cat-1','sub-2')
Insert into #T Values ('cat-1','sub-3')
Insert into #T Values ('cat-2','sub-4')
Insert into #T Values ('cat-2','sub-5')
SELECT CAT AS CATEGORYMAIN, '["' + STRING_AGG(SUB, '","')+ '"]' AS SUB
FROM #T GROUP BY [CAT]
As Martin suggested, we can use string_agg directly like:
select
[categoryMain] = [category],
[categorySub] = '["' + (select string_agg(categorySub, '","') + '"]'
from someTable
group by [category]

I want to write a sqlcmd script that pulls data from a database and then manipulates that data

I'm trying to find examples of sqlcmd script files that will run a select statement, and return those values internal to the script and place them in a variable. I then want to iterate over those returned values, run some if statements on those returned values, and then run some sql insert statements. I'm using Sql Server Managment Studio, so I thought I could run some scripts in the sqlcmd mode of the Query Editor. Maybe there's a better way to do it, but that seemed like a good solution.
I've looked on the Microsoft website for sqlcmd and T-SQL examples that might help. I've also done general searches of the web, but all the examples that come up are too simplistic, and weren't helpful. Any help would be appreciated.
Here is how I understand your starting position:
create table #data
(
id int,
column1 varchar(100),
column2 varchar(100),
newcolumn int
)
create table #lookup
(
id int,
column1 varchar(100),
column2 varchar(100)
)
insert into #data
values
(1, 'black', 'duck', NULL),
(2, 'white', 'panda', NULL),
(3, 'yellow', 'dog', NULL),
(4, 'orange', 'cat', NULL),
(5, 'blue', 'lemur', NULL)
insert into #lookup
values
(1, 'white', 'panda'),
(2, 'orange', 'cat'),
(3, 'black', 'duck'),
(4, 'blue', 'lemur'),
(5, 'yellow', 'dog')
select * from #data
select * from #lookup
Output:
select * from #data
/------------------------------------\
| id | column1 | column2 | newcolumn |
|----|---------|---------|-----------|
| 1 | black | duck | NULL |
| 2 | white | panda | NULL |
| 3 | yellow | dog | NULL |
| 4 | orange | cat | NULL |
| 5 | blue | lemur | NULL |
\------------------------------------/
select * from #lookup
/------------------------\
| id | column1 | column2 |
|----|---------|---------|
| 1 | white | panda |
| 2 | orange | cat |
| 3 | black | duck |
| 4 | blue | lemur |
| 5 | yellow | dog |
\------------------------/
From this starting point, you can achieve what you are asking for as follows:
update d set d.newcolumn = l.id
from #data d
left join #lookup l on d.column1 = l.column1 and d.column2 = l.column2
alter table #data
drop column column1, column2
This will leave the tables in the desired state, with the varchar values moved out into the lookup table:
select * from #data
/----------------\
| id | newcolumn |
|----|-----------|
| 1 | 3 |
| 2 | 1 |
| 3 | 5 |
| 4 | 2 |
| 5 | 4 |
\----------------/
select * from #lookup
/------------------------\
| id | column1 | column2 |
|----|---------|---------|
| 1 | white | panda |
| 2 | orange | cat |
| 3 | black | duck |
| 4 | blue | lemur |
| 5 | yellow | dog |
\------------------------/

simplifying values in column

my table looks like this:
| col1 | col2 | col3 |
| xxx001xxx1 | ... | ... |
| xxx001xxx2 | ... | ... |
| xxx001xxx3 | ... | ... |
| xxx002xxx1 | ... | ... |
| xxx002xxx2 | ... | ... |
| xxx003xxx1 | ... | ... |
i want to update the table, so it will be look like this:
| col1 | col2 | col3 |
| 1 | ... | ... |
| 1 | ... | ... |
| 1 | ... | ... |
| 2 | ... | ... |
| 2 | ... | ... |
| 3 | ... | ... |
any suggestions?
You could use SUBSTRING:
SELECT CAST(SUBSTRING(col1, 4,3) AS INT) AS col1, col2, col3
FROM tab_name;
And UPDATE:
UPDATE tab_name
SET col1 = CAST(SUBSTRING(col1, 4,3) AS INT);
EDIT:
my table got 600 entries and i want no leading zeros for the smaller numbers
There wont't be leading zeros: Rextester Demo
This is pretty easy when the numbers are always in the right spot. For fun, here's how you' solve this for the following sample data:
Sample data
col1
--------------
xxx001xxx1
xxxx005xxx2
xxxxxx0010xxx3
xxx00015xxx1
xxx00007xxx2
xxx0033xxx1
Solution
-- sample data
declare #sometable table (col1 varchar(100));
insert #sometable
values ('xxx001xxx1'), ('xxxx005xxx2'), ('xxxxxx0010xxx3'),
('xxx00015xxx1'), ('xxx00007xxx2'), ('xxx0033xxx1');
-- solution
with prep as ( select col1, nbrStart = substring(col1, patindex('%[0-9][0-9]%',col1), 100)
from #sometable)
select col1,
nbr = cast(substring(nbrStart, 1, patindex('%[^0-9]%', nbrStart)-1) as int)
from prep;
Results
col1 nbr
---------------------------------- -----------
xxx001xxx1 1
xxxx005xxx2 5
xxxxxx0010xxx3 10
xxx00015xxx1 15
xxx00007xxx2 7
xxx0033xxx1 33

clear string in a column for specific rows

i got a table which looks like this:
| col1 | ... | colx |
---------------------
| 1 | ... | dfd |
| 1 | ... | ajd |
| 1 | ... | aad |
| 2 | ... | azd |
| 2 | ... | iod |
| 3 | ... | asd |
| 3 | ... | aod |
| 3 | ... | wsd |
| 3 | ... | asi |
i want to update the table (or create a new table), so it looks like this:
| col1 | ... | colx |
---------------------
| 1 | ... | dfd |
| | ... | ajd |
| | ... | aad |
| 2 | ... | azd |
| | ... | iod |
| 3 | ... | asd |
| | ... | aod |
| | ... | wsd |
| | ... | asi |
any suggestions?
1.First add a new identity column to your table so we can order and update duplicate duplicate values to null:
alter table yourtable
add newcol int identity
2. If you want to update duplicate values in col1 to null then:
update yourtable
set col1 = null
where newcol not in (select min(newcol) from yourtable group by col1)
3.See your result:
select
*
from
yourtable
order by
newcol asc
You can not drop the identity column that was created but then you will loose your order..
If you don't want to update anything and just need a query
1.All you need is the following query AFTER you have created a new identity column on your table
select
*
from
yourtable
where
newcol in (select min(newcol) from yourtable group by col1)
Example
Select col1 = case when RN=1 then concat('',col1) else '' end
,other
,colx
From (
Select *
,RN = Row_Number() over (Partition By col1 order by colx)
From YourTable
) A
Order by A.Col1,RN
Returns
Something like this?
DECLARE #MyTable TABLE
(
COL1 int,
COLX nvarchar(50)
)
INSERT INTO #MyTable(COL1,COLX)
VALUES
( 1 ,'dfd'),
( 1 ,'ajd'),
( 1 ,'aad'),
( 2 ,'azd'),
( 2 ,'iod'),
( 3 ,'asd'),
( 3 ,'aod'),
( 3 ,'wsd'),
( 3 ,'asi')
select ISNULL(newcol,'')as col1,COLX from (
Select COLX,cast(Case when rn = 1 then COL1 else null end as nvarchar(50))
as NewCOL from (
Select * ,Row_number() over(Partition by col1 order by col1 ) as rn from
#MyTable
)x
)y
Result:

How to rotate a table 45 degrees and save the result into another table?

I have a table.
---------
| a | b |
---------
| a | b |
---------
I want to rotate it 45 degrees(clockwise or anti-clockwise) and save it into another table. For example, if I rotate it 45 degrees anti-clockwise, it will be:
-------------
| b | | |
-------------
| a | b | |
-------------
| a | | |
-------------
Another example, when I rotate
-------------
| a | b | c |
-------------
| d | e | f |
-------------
| g | h | i |
-------------
It will change to
---------------------
| c | | | | |
---------------------
| b | f | | | |
---------------------
| a | e | i | | |
---------------------
| d | h | | | |
---------------------
| g | | | | |
---------------------
How to do this in SQL?
A fully working example (for SQL Server 2005+)
If you need it for another system, there are equivalents for the pieces of the puzzle below
row_number()
dense_rank()
un/pivot
You can find the equivalents from other Stackoverflow questions. For example, the first two are well supported by Oracle and DB2.
create table t45 (id int identity, colA char(1), colX char(1), colZ char(1))
insert t45 select 'a','b','c'
insert t45 select 'd','e','f'
insert t45 select 'g','h','i'
GO
select [1],[2],[3],[4],[5] -- for N columns, this goes to N*2-1
from
(
select value,
targetRow = row+col-1,
targetCol = ROW_NUMBER() over (partition by row+col-1 order by row)
from
(
select *,
row = DENSE_RANK() over (order by id),
col = ROW_NUMBER() over (partition by id order by
CASE source when 'colA' then 3 -- number in reverse
when 'colX' then 2
when 'colZ' then 1 end)
from t45
unpivot (value for source in (colA,colX,colZ)) upv
) x
) p -- for N columns, this goes to N*2-1
pivot (max(value) for targetCol in ([1],[2],[3],[4],[5])) pv
order by targetRow
If you need to arbitrarily apply it to any table - use dynamic SQL to generate the pattern shown above.
Shouldn't the table
---------
| a | b |
---------
| a | b |
---------
rotated 45 degrees anti-clockwise be like this?
-------------
| | b | |
-------------
| a | | b |
-------------
| | a | |
-------------
and the
-------------
| a | b | c |
-------------
| d | e | f |
-------------
| g | h | i |
-------------
something like:
---------------------
| | | c | | |
---------------------
| | b | | f | |
---------------------
| a | | e | | i |
---------------------
| | d | | h | |
---------------------
| | | g | | |
---------------------
There is no simple way of doing this directly in SQL.
I suggest you import the result into a different programming environment, such as Java, PHP, Python or what ever, solve the problem in this context, and then (if necessary) put the result back into the DB.
Option for SQLServer2008+ with CROSS APPLY and PIVOT operators
CREATE TABLE dbo.test77
(
id int IDENTITY,
colA char(1),
colB char(1),
colC char(1)
)
INSERT dbo.test77
VALUES('a','b','c'),
('d','e','f'),
('g','h','i')
SELECT [1], [2], [3], [4], [5]
FROM (
SELECT COALESCE(o.colA, o.colB, o.colC) AS Val,
'Col' + CAST(ROW_NUMBER() OVER (ORDER BY id) AS nvarchar(1)) AS ColName
FROM dbo.test77 t CROSS APPLY (
VALUES(colA, NULL, NULL),
(NULL, colB, NULL),
(NULL, NULL, colC)
) o(colA, colB, colC)
) p
PIVOT (
MAX(Val) FOR ColName IN ([Col1], [Col2], [Col3], [Col4], [Col5], [Col6], [Col7], [Col8], [Col9])
) pvt CROSS APPLY (
VALUES ([Col3], NULL, NULL, NULL, NULL),
([Col2], [Col6], NULL, NULL, NULL),
([Col1], [Col5], [Col9], NULL, NULL),
([Col4], [Col8], NULL, NULL, NULL),
([Col7], NULL, NULL, NULL, NULL)
) o([1], [2], [3], [4], [5])
Demo on SQLFiddle