Transform data in rows to columns - sql

I'm trying to transform data of the following form:
| ID | X | Y |
--------------
| 1 | a | m |
| 1 | b | n |
| 1 | c | o |
| 2 | d | p |
| 2 | e | q |
| 3 | f | r |
| 3 | g | s |
| 3 | h | |
To this form:
| ID | X1 | X2 | X3 | Y1 | Y2 | Y3 |
------------------------------------
| 1 | a | b | c | m | n | o |
| 2 | d | e | | p | q | |
| 3 | f | g | h | r | s | |
What is the best way to accomplish this in SQL Server 2017? Is there a better way to do transformations like this using another tool?

I don't think you can solve this problem on the DB side. You should do some backend programming. You would be able to use Pivot function, if you wanted to reverse your row values as column but you want to group them based on duplicate ids. I would solve this problem by checking duplicates by using the query below. At the results of that query, you'll be able to get max count for duplicated id. For example 1 duplicated 3 times, so you need to create a data table with 3x2+1=7 columns in your backend code. 1 stands for id column. After that you can just fill that table by checking data for each id.
WITH Temp (id, count)
AS
(
Select id, count(*)
from MyTable
group by id
having count(*)>1
)
select max(count) from Temp

Related

How to select distinct records based on a given condition?

I have the following table in the MySQL database:
| id | col | val |
| -- | --- | --- |
| 1 | 1 | y |
| 2 | 1 | y |
| 3 | 1 | y |
| 4 | 1 | n |
| 5 | 2 | n |
| 6 | 3 | n |
| 7 | 3 | n |
| 8 | 4 | y |
| 9 | 5 | y |
| 10 | 5 | y |
Now I want to distinctly select the records where all the values of similar col are equal to y. I tried both the following queries:
SELECT DISTINCT `col` FROM `tbl` WHERE `val` = 'y'
SELECT `col` FROM `tbl` GROUP BY `col` HAVING (`val` = 'y')
But it's not working out as per my expectation. I want the result to look like this:
| col |
| --- |
| 4 |
| 5 |
But 1 is also being included in the results with my queries. Can anybody help me building the correct query? As far as I understand, I may need to create a derived table, but can't quite figure out the right path.
You are close, with the second query. Instead, compare the min and max values:
SELECT `col`
FROM `tbl`
GROUP BY `col`
HAVING MIN(val) = MAX(val) AND MIN(`val`) = 'y';
Check that 'y' is the minimum value:
HAVING MIN(val) = 'y'

Consolidate duplicate rows based on subgrouping

I have a table of temporal values in which there exist repeated values in groupings, but I want to remove all but one for each grouping and maintain the order (can't just say the distinct values).
If the sequence of rows was as such in order
+------+-----+
| time | col |
+------+-----+
| 1 | A |
| 2 | A |
| 3 | A |
| 4 | B |
| 5 | B |
| 6 | B |
| 7 | C |
| 8 | D |
| 9 | E |
| 10 | A |
| 11 | A |
| 12 | B |
+------+-----+
Then it should be resulted as
+-----+
| col |
+-----+
| A |
| B |
| C |
| D |
| E |
| A |
| B |
+-----+
Is there a way to do this without a cursor? How I would do it in not SQL would be to iterate over the list and say if the current index matches the previous index, then pop it.
SQL tables represent unordered sets. The rows you want to remove depend on the ordering, specifically adjacent identical values are being removed.
In order to have an ordering, the data needs a column that specifies it. Let me assume you have one.
If so, this is easily handled with lag():
select col
from (select t.*, lag(col) over (order by orderingcol) as prev_col
from t
) t
where prev_col <> col or prev_col is null;

get X number of non null columns as single string

I am trying to find the SQL command to do something but I don't know how to explain it so I'll use an example. I have a table like so:
| one | two | three | four |
|-----|-----|-------|------|
| a | h | i | j |
| b | k | l | |
| c | m | n | o |
| d | p | | |
| e | q | | |
| f | r | s | |
| g | t | | |
I need to create new columns that take the first non-null column from the right and kind of reverse it going up and joining/concatenating the fields.
| one | 1-up | 2-up | 3-up |
|-----|------|------|---------|
| a | j | j, i | j, i, h |
| b | l | l, k | |
| c | o | o, n | o, n, m |
| d | p | | |
| e | q | | |
| f | s | s, r | |
| g | t | | |
For b, since column four doesn't have data it uses three as the first value. Same for the other rows.
I hope this makes sense. I'm not sure how else to explain this.
You can use COALESCE like this :
select one, COALESCE(four,three,two,'') as '1-up',
COALESCE(four+','+three,three+','+two,'') as '2-up',
COALESCE(four+','+three+','+two,'') as '3-up'
from Table1
SQL Fiddle link Here

SQL get interection of values across multiple rows grouped by primary key

I have table with data as follows
+----+------+
| id | code |
+----+------+
| 1 | M |
| 1 | Y |
| 2 | M |
| 2 | S |
| 3 | M |
| 3 | Q |
+----+------+
I would like to know if its possible to write a query that would return a list of codes that are unique to each ID? If there is no intersection the query should return no rows.
In the example above the only value common to all is M.
+----+------+
| id | code |
+----+------+
| 1 | M |
| 1 | S |
| 2 | M |
| 2 | S |
| 2 | H |
| 3 | M |
| 3 | S |
| 3 | Q |
+----+------+
The above would return M and S, common to all three ID's
Thanks
Try this:
SELECT code
FROM mytable
GROUP BY code
HAVING COUNT(*) = (SELECT COUNT(DISTINCT id) FROM mytable)
The above query assumes that code can appear only once per id.

Vertical & Horizontal Tables in SQL Server 2005

Please condider the situation in which there are two tables, Body and File, in which every record of the first one has zero or more corresponding records in the second one:
BodyID | Body
-------------
1 | X
2 | Y
FileID | BodyID | File
------------------------
1 | 1 | A
2 | 1 | B
3 | 2 | C
4 | 2 | D
5 | 2 | E
Of course, it is pretty easy to join both tables and get something like
BodyID | FileID | Body | File
-----------------------------
1 | 1 | X | A
1 | 2 | X | B
2 | 3 | Y | C
2 | 4 | Y | D
2 | 5 | Y | E
However, what I would like to be able to do is to transform this same table into an horizontal one, like
BodyID | Body | File1 | File2 | File3 | ...
-------------------------------------------
1 | X | A | B | NULL | ...
2 | Y | C | D | E | ...
where each column is replaced by NULL (or any other "meaningful" value) when there are no files. The problem is that I can neither use D-SQL nor cursors. Can anyone please help me out?
whenever you need to convert your rows into columns then use pivot.you can search msdn for pivot.