Sort columns based on data in tuples mysql - mysql

Say, I have a table
A B C D E F
1 2 4 3 6 5
4 2 3 1 6 5
4 5 3 6 1 2
How can one get an output based on rearranging based on its data. For example,
ABDCFE
DBCAFE
EFCABD
is it possible?
EDIT:
The question seems to be asking: How can I get the list of column names in order by value?

I got it. You want to sort the values in each row and show the names of the columns in order.
Let me assume that you have a row id, so you can identify each row. Then:
select id, group_concat(which order by val) as ordered_column_names
from ((select id, a as val, 'A' as which from t) union all
(select id, b, 'B' as which from t) union all
(select id, c, 'C' as which from t) union all
(select id, d, 'D' as which from t) union all
(select id, e, 'E' as which from t) union all
(select id, f, 'F' as which from t)
) t
group by id
order by id;

SQL is fundamentally not the tool to do the operation you describe, because it violates the concept of a relation. I don't mean the common use of "relation" meaning a relationship, I mean the mathematical definition of relation.
There is no order of columns in a relation. The columns are a set, which is by definition unordered. Columns are identified by their name, not their position left-to-right.
All the entries in rows under each respective named column must be part of the same data domain. If you mix them around on a row-by-row basis, you're violating this.
I guess all your columns A through F are actually using values in the same data domain, or else reordering them wouldn't make any sense. If this is true, then you're violating First Normal Form by defining a table with repeating groups of columns. You should instead have all six columns be in one column of a second table. Then it becomes very easy to sort them by value.
Basically, what you're trying to do is better solved by formatting the data results in some application code.

There is a way to do it ,get coulmn name by column ordinal order and print it.
For each value in coulmn iterate this and get the column name for the ordinal specified in cloumn data. Here ordinal position is value in each coulmn data. Iterate for each row and each column and your problem is solved.
select column_name
from information_schema.columns
where table_name = 'my_table_name' and ordinal_position = 2;

It appears that you are asking for output where each row in the output is just a specification of the order of the data values in the columns.
Then, if the values are always integers between 1 and 5, you can do it by outputting a character value of 'A' where the data value is 1, a 'B' where the data value is 2, etc. This SQL will do that.
Select Char(A+64)A, Char(B+64) B,
Char(C+64) C, Char(D+64) D,
Char(E+64) E, Char(F+64) F
From table
if the want the column sort order in one output column, you could also do this:
Select Char(A+64) + Char(B+64) +
Char(C+64) + Char(D+64) +
Char(E+64) + Char(F+64) SortOrder
From table

Related

SSRS access fields in a dataset

I want to write a SSRS expression that will allow me to grab the value from Column B base on the max value from ColumnA.
For Example, I have the following values
ColumnA
ColumnB
1
Test
2
Tester
3
Testing
=FIRST(
iif(
Fields!ColumnA.Value= MAX(Fields!ColumnA.Value,"test"),
Fields!ColumnB.Value,0
),"test"
)
The reason I am doing this is because I am trying to combine to datasets in one table. Certain fields in the table just needs to select top N values from another dataset.
I think that easiest way is to add something like row_number into your sql query (row_number() over (order by ColumnA desc) rn and then you can have condition iif(fields!rn.value = 1, fields!ColumnB.value,0)

Converting multivalued column in table A to multiple rows in table B Mysql

Given 2 tables, I want to convert the multivalued row in table 1
Given 2 tables
Table A
id value
ae [1,2,4,5]
ac [1,6]
Table B
id value
ae 1
ae 2
ae 4
ae 5
ac 1
ac 6
I know I have to insert a before insert trigger on table B, but I cannot figure out the logic.
Another way to convert JSON arrays in MySQL into rows (I assume "value" column in table A is json array type). Transform Table A into Table B.
MySql >= 8.0:
First with a recursive query I get json array indexes for each json array with a length > 0 (a row per index), then I join table A with indexes query and used JSON_EXTRACT() to extract each json array value in a row.
WITH RECURSIVE indexes AS (SELECT id, 0 AS json_index FROM A WHERE JSON_LENGTH(value) > 0
UNION ALL
SELECT i.id, i.json_index + 1
FROM indexes i
INNER JOIN A ON A.id = i.id AND i.json_index < JSON_LENGTH(A.value) - 1
)
SELECT A.id, JSON_EXTRACT(A.value, CONCAT('$[', i.json_index, ']')) AS arrayValue
FROM A
INNER JOIN indexes i ON A.id = i.id;
Here's an idea:
Get the total of value need to be separated using LENGTH():
Take the first example [1,2,4,5]. There are 4 values separated by commas here. If we do LENGTH(value), we will get 9 as there are 9 characters including [ and ,. Then we do LENGTH(REPLACE(value,',','')) which we replace the commas from the values with nothing and this will give us 6. If we subtract them, we'll get 3 which we suppose to get 4 so we add +1 in the final calculation. We end up with something like this:
(LENGTH(value)-LENGTH(REPLACE(value, ',', '' )))+1
With that, you'll get ae with 4 and ac with 2. From here there are three usage of this information:
To make a numbering sequence referring to the largest number we get, in this case 4.
To return repeated row based on how many length the value column has.
To be used in SUBSTRING_INDEX() function and return the value accordingly.
In the end, I've managed to create two queries using the same idea but for a different MySQL version.
For older MySQL version (before v8), this might do:
SELECT id,
SUBSTRING_INDEX(SUBSTRING_INDEX(val,',',ln),',',-1) AS value
FROM
(SELECT 1 AS ln UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) RN
LEFT JOIN
(SELECT id,
REPLACE(REPLACE(value,'[',''),']','') AS val
FROM tableA) A
ON ln<=(LENGTH(val)-LENGTH(REPLACE(val,',','')))+1
ORDER BY id, value;
However, the issue here is that the hardcoded numbering sequence by rows on this part of the query ..(SELECT 1 AS ln UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) RN... Meaning that if there's a value where the length is everchanging, then this part need to be constantly edited.
For MySQL v8 (but not quite v8.0.4 that supports JSON_TABLE):
WITH RECURSIVE cte AS (
SELECT 1 AS ln, MAX((length(value)-length(replace(value,',','')))+1) AS totval
from tableA UNION ALL
SELECT ln+1, totval FROM cte WHERE ln+1 <= totval)
SELECT id,
REGEXP_REPLACE(SUBSTRING_INDEX(SUBSTRING_INDEX(value,',',ln),',',-1),'[^0-9]','') AS value
FROM cte
LEFT JOIN tableA
ON ln<=(length(value)-length(replace(value,',','')))+1
ORDER BY id, value;
Here I'm using WITH RECURSIVE function to dynamically generate the numbering sequence, which means that if the length is more than 4, there's no need to edit the query.
Demo fiddle

MySQL conditional concatenate based on multiple columns

I'm stumped on a proper query to get an output based on multiple columns and the conditions in those columns:
a b c
1 x x
2 x x
3 x
I would like the results to output, based on where the x's are in columns a, b and c:
1 a,c
2 a,b
3 a
Is this possible to do in mysql? Much appreciated
You can use the CONCAT_WS function (docs) and some IF statements.
SELECT tn.ID,
CONCAT_WS(
',',
IF(tn.a='x','a',null),
IF(tn.b='x','b',null),
IF(tn.c='x','c',null)
) as result
FROM TableName tn;
You can use IFNULL function for that (docs). For example:
SELECT a, IFNULL(b, c) FROM table_name;
It will select a for every case and conditionally b or c, depending on it's value (it have to be not null). But I'm afraid you cannot do more than that.

What is this SQL query syntax mean?

SELECT b.*,
( select a.USER_NAME
from A.db.USER a
where a.USER_ID=b.Booking_Inspector
) as USER_NAME
FROM A.dbo.Booking b
where b.Booking_Inspector=? and b.confirm=1
From this sql syntax, what is "," which after "*" mean?
and anyone can explain this query to me or tell me where I can start?
It means all the columns from table Booking, and to the far right (the last column per row) bring in the user_name column from table user relating on the user.user_id matching the booking.booking_inspector. Such that the Booking.confirm is 1, and Booking_inspector is filled in with a parameter passed.
So it limits the rows of output to confirm is 1 and Booking_Inspector is the parameter passed (or bound, etc) depending on the language calling it.
Select * means all columns. So all columns from the one table, and just one column from the other
In this case, (select a.USER_NAME from A.db.USER a where a.USER_ID=b.Booking_Inspector) is the subquery which will return column a.USER_NAME. So this query is selecting everything from b (b.*) and the column a.USER_NAME from the subquery. So like you put comma between column names in select query, it is same.
select all columns from b and one more column from that subquery as USER_NAME.
( select a.USER_NAME
from A.db.USER a
where a.USER_ID=b.Booking_Inspector
) as USER_NAME
That whole thing above as 1 column
SELECT b.*, [USER_NAME]
FROM A.dbo.Booking b
where b.Booking_Inspector=? and b.confirm=1

selecting column names where data is not null or blank

SQL Server 2008
I have a table MyTable with columns A, B, C, D
When I select a row I want a list of only those columns with non-null/blanks. The result set would be
A
C
D
if B was null in my row.
Actually, there may be a column E someday. But I can get all possible column names from another table and need to check if MyTable has any of them and if so which ones have data for the row I selected
Thus:
select * from MyTable where ID = 6
select ColumnName from AllColumnNames
For each ColumnName in the result
if ColumnName exists in MyTable AND there is data in it where ID = 6, add ColumnName to output.
There's gotta be a way to do this in one query?
This will convert your table to XML in the CTE and then it uses XQuery to find the node names that does not have empty values. This will work if your column names does not break the rules for XML node names.
;with C(TableXML) as
(
select *
from MyTable
where ID = 6
for xml path('T'), elements xsinil, type
)
select T.X.value('local-name(.)', 'sysname') as ColumnName
from C
cross apply C.TableXML.nodes('/T/*') as T(X)
where T.X.value('.', 'nvarchar(max)') <> ''
Try here: https://data.stackexchange.com/stackoverflow/query/59187
Add this the the where clause if you want to exclude the ID column as well.
T.X.value('local-name(.)', 'sysname') <> 'ID'