Select all cell values of a single row table and list it as separate row in SQL - sql

I've a table like this
ID col1 col2 col3 col4
---------------------------------------------------
1 a b c d
2 e f g h
So if I pass the ID 2 it should return all the colum values as separate rows as this
Colum Value
---------------------
ID 2
Col1 e
col2 f
col3 g
col4 h
So all the cells of that single rows been splitted as separate rows.
How can I accomplish this

One way to do it with unpivot and union all.
select 'id' as colu,cast(id as varchar(255)) as val from t where id=2
union all
select colu,val
from t
unpivot (val for colu in (col1,col2,col3,col4)) u
where id=2

You can use cross apply as below:
Select Id as [Column], [Value] from yourcols
cross apply (values(col1), (col2), (col3), (col4)) rws([Value])
where Id = 2

Please refer the below stack over flow link SQL query to split column data into rows
found the question identical as yours.

Related

sql query help, don't know how to term this

I'm not too sure how to term this question. Stay with me.
I want to create a query to retrieve the rows with x's in the row column in the table(this is a dummy table):
row col1 col2 col3
x 1 a c
x 2 b c
x 3 a c
4 b d
x 5 f g
So the way I want my query to work is to retrieve all rows where the value for col2 doesn't have a row in col3 where the value is d. Ie. value 'a' will be retrieved because it only has c's for col3, but value 'b' wont be retrieved because it has a d in col3 on the 4th row down.
I hope this is easy to understand.
Ps. Once I know how to do the query I expect I'll know how to phrase the title and will redo it. (although now I think about it, maybe this title is best for all those with questions like mine)
Based on everything you've provided, I'll have to make a few assumptions. Short of doing a self-join on the table, you could take advantage of an identity key on the table to use a simple query as such:
SELECT * FROM TABLE_NAME
WHERE id NOT IN (SELECT id FROM TABLE_NAME WHERE col3 = 'd');
If you don't have an identity key on the table, you could do something more like this:
SELECT * FROM TABLE_NAME
WHERE col2 NOT IN (SELECT col2 FROM TABLE_NAME WHERE col3 = 'd');
Both of these queries will return all tuples in the relation that have elements of col2 that are not in tuples where col3 contains 'd'.
Think of how you might do this manually, and put that into your query.
To get all the col3 values you'd write:
SELECT DISTINCT col3 FROM TABLE_NAME
Use that to filter rows from your selection via a not in clause:
SELECT
col1, col2, col3 FROM TABLE_NAME
WHERE col2 not in (SELECT DISTINCT col3 FROM TABLE_NAME);

How to remove duplicate values from a table

I'm working on pulling data to a table which has two data sets of data loaded to temp table and finally inserts into table. There are 2 records which are duplicates but i need both the records if their value on one column is same else delete it. Col1 and col4 are primary keys
col1 col2 col3 col4
--------------------
a ab abc x
a ab abc y
b ab abc y
b ab abc z
what i want is forget about col 2 and col3, check in col1 if row 1 and row 2 are same it should go check col4 and if row1 and row 2 are different it should display both row1 and row 2 even if row 2 and row 3 in col4 are same. so if the records are as i mentioned it should allow all 4 values but with the logic i wrote it is returning row1,row3,row4 because it is considering row2 and row3 of col 1 with row 2 row 3 of col 4 and displaying only 3 records but i want all records. Please help me how to write a logic in sql for this situation.
Based on what I have understood from your question, you could do something like this..
DELETE i
FROM YourTable i INNER JOIN
(
SELECT col1,col4
FROM YourTable
GROUP BY col1,col4
HAVING count(col2)>1
) t ON t.col1 = i.col1 AND t.col4 = i.col4
Live Demo Here
Or if ou want to keep only one record and remove other duplicate records, you could do like this..
;with cte as
(
SELECT *,row_number() over(partition by col1,col4 order by col1,col4) as rn
FROM YourTable
)
DELETE from cte where rn>1
Live Demo Here

SQL group data (find data family)

Please help me, I need to find out a SQL solution for grouping data using SQL Server database.
I'm pretty sure that it could be done in one SQL request but I can't see the trick.
Let' see the problem :
I have a two columns table (please see below an example). I just want to add a new column containing a number or a string which indicates the group
BEFORE :
Col1 | Col2
-----+-----
A | B
B | C
D | E
F | G
G | H
I | I
J | U
AFTER TRANSFORMATION :
Col1 | Col2 | Group
-----+------+------
A | B | 1
B | C | 1
D | E | 2
F | G | 3
G | H | 3
I | I | 4
J | U | 5
In other words: A, B, C are in the same group; D and E too; F, G, H in group 3 ....
Do you have any lookup table to get this group mapping?
Or if you just have a logic defined to decide a group, i would recommend to add a UDF which will return group for supplied values.
SELECT Col1,Col2,GetGroupID(Col1,Col2) AS Group
FROM Table
Your UDF will be something like following
CREATE FUNCTION GetGroupID
(
-- Add the parameters for the function here
#Col1 varchar(10),
#Col2 varchar(10)
)
RETURNS int
AS
BEGIN
DECLARE #groupID int
IF (#Col1="A" AND #Co2 = "B") OR (#Col1="B" AND #Co2 = "C")
BEGIN
SET #groupID = 1
END
IF #Col1="D" AND #Co2 = "E"
BEGIN
SET #groupID = 2
END
-- You can write saveral conditions in the same manner.
return #groupID
END
However, in case you have this mapping defined somewhere in another table, let us know the structure of the table and we can then update the query to join with that table instead of using UDF.
Considering the performance of the query, if the amount of data is huge in your table , it is recommended to have these mappings to one fix table and Join that table in query. Using UDF may harm performance if data amount is huge.
There is absolutely no need for a UDF here. Regardless of whether you are looking to update the table with a new column or simply pull out the data with the grouping applied, you will be best off using a set based solution, ie: create and join to a table.
I am assuming here that you don't have messy data, such as a row with Col1 = 'A' and Col2 = 'F'.
If you are able to add new tables permanently you can use the following to create your lookup table:
create table Col1Groups(Col1 nvarchar(10), GroupNum int);
insert into Col1Groups(Col1,GroupNum) values ('A',1),('B',1),('C',1),('D',2),('E',2),('F',3),('G',3),('H',3);
and then join to it:
select t.Col1
,t.Col2
,g.GroupNum
from Table t
inner join Col1Groups g
on t.Col1 = g.Col1
If you can't, you can just create a derived table via a CTE:
with Col1Groups as
(
select Col1
,GroupNum
from (values('A',1),('B',1),('C',1),('D',2),('E',2),('F',3),('G',3),('H',3)) as x(Col1,GroupNum)
)
select t.Col1
,t.Col2
,g.GroupNum
from Table t
inner join Col1Groups g
on t.Col1 = g.Col1
You get the first rows per group with
select col1, col2 from mytable where col1 not in (select col2 from mytable) or col1 = col2;
We can give these rows numbers with
rank() over (order by col1) as grp
Now we must iterate through the rows to find the ones belonging to those first ones, then those belonging to these, etc. A recursive query.
with cte(col1, col2, grp) as
(
select col1, col2, rank() over (order by col1) as grp
from mytable where col1 not in (select col2 from mytable) or col1 = col2
union all
select mytable.col1, mytable.col2, cte.grp
from cte
join mytable on mytable.col1 = cte.col2
where mytable.col1 <> mytable.col2
)
select * from cte
order by grp, col1;
Additional answer for a more flexible approach
Originally you asked for chains A|B -> B|C, F|G -> G|H etc., but in your comment to my other answer you introduced forks like A|B -> B|C, B|D and I've adjusted my answer.
If you want to go one step further and introduce net-like relations such as A|B -> B|C, D|C, we can no longer follow chains forward only (in the example D belongs to the A group, because though A doesn't lead to D directly, it leads to C and D also leads to C. Here is a way to solve this:
Get all letters from the table (no matter whether in col1 or col2). Then for each of them find related letters (again no matter whether in col1 or col2). And for these again find related letters and so on. That will give you complete groups. But duplicates (as D is in the A group, A is in the D group also), which you can get rid of by simply taking the smallest (or greatest) group key per letter. Then join the Groups to the table.
The query:
with cte(col, grp) as
(
select col, rownum as grp from
(select col1 as col from mytable union select col2 from mytable)
union all
select case when mytable.col1 = cte.col then mytable.col2 else mytable.col1 end, cte.grp
from cte
join mytable on cte.col in (mytable.col1, mytable.col2)
where mytable.col1 <> mytable.col2
)
cycle col set is_cycle to 'y' default 'n'
select mytable.col1, mytable.col2, x.grp
from mytable
join (select col, min(grp) as grp from cte group by col) x on x.col = mytable.col1
order by grp, col;

SQL - Select from column A based on values in column B

Lets say I have a table with 2 columns (a, b) with following values:
a b
--- ---
1 5
1 NULL
2 NULL
2 NULL
3 NULL
My desired output:
a
---
2
3
I want to select only those distinct values from column a for which every single occurrence of this value has NULL in column b. Therefore from my desired output, "1" won't come in because there is a "5" in column b even though there is a NULL for the 2nd occurrence of "1".
How can I do this using a TSQL query?
If I understand correctly, you can do this with group by and having:
select a
from t
group by a
having count(b) = 0;
When you use count() with a column name, it counts the number of non-NULL values. Hence, if all values are NULL, then the value will be zero.
It's fairly simple to do:
SELECT A
FROM table1
GROUP BY A
HAVING COUNT(B) = 0
Grouping by A results in all the rows where the value of A is identical to be transferred into a single row in the output. Adding the HAVING clause enables to filter those grouped rows with an aggregate function. COUNT doesn't count NULL values, so when it's 0, there are no other values in B.
Two more ways to do this:
SELECT a
FROM t
EXCEPT
SELECT a
FROM t
WHERE b IS NOT NULL ;
This would use an index on (a, b):
SELECT a
FROM t
GROUP BY a
WHERE MIN(b) IS NOT NULL ;
Try it like this:
DECLARE #tbl TABLE(a INT, b INT);
INSERT INTO #tbl VALUES(1,5),(1,NULL),(2,NULL),(2,NULL),(3,NULL);
--Your test data
SELECT * FROM #tbl;
--And this is what you want - hopefully...
SELECT DISTINCT tbl.a
FROM #tbl AS tbl
WHERE NOT EXISTS(SELECT * FROM #tbl AS x WHERE x.a=tbl.a AND b IS NOT NULL)
To turn your question on it's head, you want the values from column a where there are no non-null values for that value in column b.
select distinct a
from table1 as t1
where 0 = (select count(*)
from table1 as t2
where t1.a = t2.a
and b is not null)
Sample fiddle is here: http://sqlfiddle.com/#!6/5d1b8/1
This should do it:
SELECT DISTINCT a
FROM t
WHERE b IS NULL
AND a NOT IN (SELECT a FROM t WHERE b IS NOT NULL);

Fetching multiple rows based on two comparisons in each row

I have a table as follows
col1 col2 col3
a 01/01/2001 1.1
a 01/02/2001 1.2
a 01/03/2001 1.3
b 02/03/2004 2.1
b 02/04/2004 2.2
b 02/05/2004 2.3
I want to be able to fetch rows based on multiple comparisons on each row. That is, fetch rows where I have (a,01/01/2001) and (b,02/05/2004). Something that would look like,
Select * from table where col1,col2 in (('a','01/01/2001'),('b','02/05/2004'))
How can I do this?
SELECT *
FROM table
WHERE
(col1 = 'a' AND col2 = '01/01/2001')
OR
(col1 = 'b' AND col2 = '02/05/2004')
Your original code was so close but not quite there. You just needed to put the fields on the left hand side of the condition in brackets
Select * from table where (col1,col2) in (('a','01/01/2001'),('b','02/05/2004'))