MySQL Splitting Column Results into Dynamic Columns in View - mysql

I'm not sure if this is possible using MySQL alone, or whether PHP or similar would be required. What I am trying to produce is a view that is dependent upon the amount of information that is present in one table to determine how many columns are displayed in the view.
I have a Components table containing the following fields:
CM_ID (The component ID)
CM_CODE (A specific company assigned code)
CM_DESCRIPTION (A brief description of the component)
FORMAT_ID (A referenced FK)
ITEM_ID (A referenced FK)
An example of a select from the Component table is:
CM_ID CM_CODE CM_DESCRIPTION FORMAT_ID ITEM_ID
1 111111 Technical Manual 1 (280 Page A4 Book) 32
2 111112 Schematic Diagram 2 (A3 Fold-out sheet) 32
3 222223 Technical Manual 1 (280 Page A4 Book) 2
4 222224 Price Guide 25 (32 Page A4 Book) 2
5 333335 Instruction Manual 33 (220 Page A5 Book) 44
The view I'm trying to get is based upon displaying items (from the master items table). Each item will have one or many components (which are brought in with an FK on CM_ID)
I have produced the following view:
SELECT i.item AS Item,
GROUP_CONCAT(DISTINCT CONCAT(cm.CM_CODE, _utf8', ',cm.CM_DESCRIPTION, _utf8,', ',f.FORMAT_DESCRIPTION) SEPARATOR '; ') AS Components
FROM item AS i
JOIN components AS cm ON i.ITEM_ID = cm.ITEM_ID
JOIN format AS f ON cm.FORMAT_ID = f.FORMAT_ID
This will obtain results in the form of:
Item Components
2 222223, Technical Manual, 164 Page A4 Book; 222224, Price Guide, 32 Page A4 Book
32 111111, Technical Manual, 280 Page A4 Book; 111112, Schematic Diagram, A3 Fold-out
44 333335, Instruction Manual, 220 Page A5 Book
Only the 2 columns are returned (Item & Components), due to the concatenation. What I'd like to be able to do is to form separate columns for the item's components that are dependent upon the actual amount of components.
Example output:
Item Component1 Component2
2 222223, Technical Manual, 164 Page A4 Book 222224, Price Guide, 32 Page A4 Book
32 111111, Technical Manual, 280 Page A4 Book 111112, Schematic Diagram, A3 Fold-out Sheet
44 333335, Instruction Manual, 220 Page A5 Book
Note that Item 44 only has one component, therefore, it has no data in the component2 column. Should a select be done on JUST item 44, then ideally, there would be no mention of the Component2 column at all. Similarly, if another item came along with 4 components, then the output would automatically scale to form 4 Component columns.
I've looked at a number of ways to acheive this, but none seems to be exactly right. Is this possible?
Many Thanks in advance
Iain
UPDATE **
Ok, I'm trying to set a defined number of columns and do the select on that but still having difficulty. I've added another field to the Components table:
CM_ORDER
Which can be used to differentiate between components for the same item (in theory).
I know this isn't right, but I was trying to get something along the lines of the following to work:
SELECT i.item AS Item,
cm.CM_CODE AS Component_Code1 WHERE cm.CM_ORDER = 1,
cm.CM_DESCRIPTION AS Component_Description1 WHERE cm.CM_ORDER = 1,
cm.CM_CODE AS Component_Code2 WHERE cm.CM_ORDER = 2,
cm.CM_DESCRIPTION AS Component_Description2 WHERE cm.CM_ORDER = 2
FROM item AS i
JOIN components AS cm ON i.ITEM_ID = cm.ITEM_ID
JOIN format AS f ON cm.FORMAT_ID = f.FORMAT_ID
Not sure how I'd get the associated "Format" info in there too. Obviously, MySQL isn't at all happy with me putting multiple WHERE clauses in the SELECT statement so I tried using CASE instead, with as much success (none).
There must be a way to split it out into separate columns in the same query without using a scripting/coding language.
Trying to achieve the result:
Item Component_Code1 Component_Description1 Component_Code2 Component_Description2
2 222223 Technical Manual 222224 Price Guide
32 111111 Technical Manual 111112 Schematic Diagram
44 333335 Instruction Manual
with the associated "Format" data too.
Am hoping that this can be done
Cheers
Iain

Strictly speaking, what you want to do is not possible in SQL. SQL requires that the columns in a query be pre-defined.
One possible approach is to use dynamic SQL for this purpose. You would calculate the maximum number of components in the data, and then use this information to create a query.
You already are trying the second approach, which is to use semi-colon separated lists of comma-separated lists.
The final approach is to settle on some maximum number of components, and build the query for that. So, you could show, say, the first three components.

Related

SSRS Multi Column Report Row Visibility

Using the faking multi-column report using tables method here:[https://stackoverflow.com/questions/10882784/ssrs-how-to-continue-data-to-next-column]
I need a report to show multiple columns sorting my data across and then down the page. I need page breaks by Category and the title of each category to repeat on the page.
I have 4 identical tablixes across my page with =IIF((RowNumber(Nothing) Mod 4) = 1, False, True) ect. in the row visibility and a sort on $. The 4 tablixes are wrapped in a list that is grouped by Category with a page break between each group.
Here are my issues if you can help:
If I just have my 4 tablixes across the page with the sort it works fine and sorts properly.
When I try to add the page break and grouping, I get the sort wrong. The page will break by category but if the data in a grouping doesn't end in the 4th column the next page seems to start where the previous page ended. For example, page 1 ends in column 3 so page 2 starts with column 4 instead of 1. How can I adjust this so the next page always starts in the 1st position with the highest $ by category.
If the category goes more that 1 page - I lose the headings.
Update: the OP has explained that their problem is that they aren't using SQL at all, this is a DAX problem. So I will update my (already lengthy) instructions for how to do this, with a followup article that deals with the same problem but using DAX instead of SQL to get the required columns to do this work properly.
For anybody who is just casually interested, the short answer resolution is that this is hard to do with a lot of tweaking of specialized design objects in the RDL, and it's not very extensible that way, because you're going to have to hardcode your individual column-tablixes in the designer. BUT it quite easy to do with a dataset that contains proper column and row index values; you only need ONE tablix and you can dynamically set up the number of columns without a bunch of work. Then you group by the row index and the column index, you're done.
So, in the OP's case, the problem is getting those two index values into the dataset. I found this pretty straightforward -- in fact, doing it allowed me to go back and somewhat simplify the required SQL as well -- EXCEPT :
If the report requires a row grouping to be included in the designer object it's more difficult to get the column and row index values to be appropriate to the group level values that you will need. In SQL, this is just a simple case of adding a PARTITION BY instruction, but there are numerous articles on the web about how to do the same thing in DAX, none of which seemed to work for me -- I'm not a DAX expert, so maybe somebody else will chime in with the right way to do that?
So, for DAX, I start with the same basic technique, I will still use one tablix, but I will add some expressions into the row and column groupings to compensate. Still pretty easy and still completely dynamic, and maybe we could do without the exception if a DAX expert wants to think over the problem. What you're looking for is a row and column assignment that looks like this (assuming 2 cols have been requested, group is needed, items are alphabetically sorted, and you need to go Down-Then-Across):
Group
Item
Row Index
Col Index:
Fruit
Apple
1
1
Fruit
Peach
2
1
Fruit
Pear
3
1
Fruit
Persimmon
1
2
Fruit
Rasberry
2
2
Veg
Carrot
4
1
Veg
Cauliflower
5
1
Veg
Green Bean
4
2
resulting in :
Group
Col 1
Col 2
Fruit
Apple
Persimmon
Peach
Rasberry
Pear
Veg
Carrot
Green Bean
Cauliflower
Or like this, matching the OP's requirement, Across-Then-Down, again assuming 2 cols and alpha sort:
Group
Item
Row Index
Col Index
Fruit
Apple
1
1
Fruit
Peach
1
2
Fruit
Pear
2
1
Fruit
Persimmon
2
2
Fruit
Rasberry
3
1
Veg
Carrot
4
1
Veg
Cauliflower
4
2
Veg
Green Bean
5
1
resulting in:
Group
Col 1
Col 2
Fruit
Apple
Peach
Pear
Persimmon
Rasberry
Veg
Carrot
Cauliflower
Green Bean
Without grouping DAX in either direction will work exactly the same way as the SQL version, and can be swapped as datasets into the same tablix with no other changes, in fact.
The OP also mentioned needing to repeat the headings, which was already anticipated in the original article and continues to work fine.
While this response is lengthy -- in hopes of getting a DAX expert to provide a way that will allow RANKX to give the right grouped index values directly in the dataset -- I'm not being coy by not working out the code details here; that will be longer, deserves to be a blog article.
So here it is: Snaking Columns for I hope the last time ever

combine 4 rows in to 1 all having unique values

In this image you can see location is combination of different columns. The output i want needs to combine sizes S,M,L,XL to a single row and it should show only one location, Basically s,m,l,xl should be considered one. Also S is supposed to be on level 01,M on level 02, L on Level 03 & XL on 04)
You can use my DJoin function for this, taken from my project VBA.DJoin.
This also includes a demo file, and you'll see an example on how to list sizes:
using a multi-value field:
However, you probably don't have that. Instead, you'll have to create a table with the sizes and a sorting order, for example:
and include that in the query you use as source with DJoin.

Report Builder 3.0 - How to add 2 columns of values both belonging to the same field

Here is the view of table in ''conception'' view:
Conception view
And here's what it gives:
Executed view
As you can see my Column group entitled [Poste_Histo___Etat_Description_Abrégé] breaks out into 3 categories when I run the report: Comblé, Vacant and Vacant_att
I want to blend Vacant and Vacant att into just 1 category and name it Vacant, so to have only 2 categories when the report is being run.
I tried multiple functions and there was one that got me close, but event then, it only renamed Vacant_att to Vacant and didn't add the 2 columns though:
=IIF(InStr(Fields!Poste_Histo___Etat_Description_Abrégé.Value, "Vacant") Or InStr(Fields!Poste_Histo___Etat_Description_Abrégé.Value, "Vacant_att"), "Vacant", "Comblé")
So my goal is to figure this out and ultimately, portray these same values on a graph in the same manner: that is to have only "Vacant" and "Comblé" as categories.
p.s. If it makes any difference, all the «Expr» are the following formula:
=Sum(IIF(InStr(Fields!Poste.Value, ""+"300") Or InStr(Fields!Poste.Value, ""+"100"), 1, 0))
It's point is to only get the values for that end with 300 or 100.
Thanks a lot to any1 who helps!
I ended up finding my answer myself lol. For any1 having eventually the same problem, here is my approach:
1- In the Query Designer pane of my dataset, I created 2 Calculated members:
One being Comblé including the [Comblé] category and the other being Vacant in which I combined [Vacant] and [Vacant_att].
2- I used the formula mentioned in my question as partly successful and replaced the 1 with the newly created calculated members correspondingly. So:
For Vacant:
=Sum(IIF(InStr(Fields!Poste.Value, ""+"300") Or InStr(Fields!Poste.Value, ""+"100"), Fields!Vacant.Value, 0))
For Comblé:
=Sum(IIF(InStr(Fields!Poste.Value, ""+"300") Or InStr(Fields!Poste.Value, ""+"100"), Fields!Comblé.Value, 0))
3- So this gave me the right numbers BUT (as per the pic attached) as long as I had [Poste_Histo___Etat_Description_Abrégé] as a Parent Group in my Tablix, which was no good since this dimension has 3 categories originaly (Vacant, Vacan att. and Comblé) I ended up with 3 columns who have 2 columns each (my newly created Calculated members - Vacant and Comblé)... so 6 columns
Table 1.0
4- Finally to tackle this issue, I created 2 columns both out of the parent group [Poste_Histo___Etat_Description_Abrégé] : Vacant2 and Comblé2. And I simply copy pasted that same formula in these but only to discover that the values were all 3 times larger (sum of the 3 columns). As a simple way out, I just divided each formula by 3 and . As so:
=(Sum(IIF(InStr(Fields!Poste.Value, ""+"300") Or InStr(Fields!Poste.Value, ""+"100"), Fields!Comblé.Value, 0)))/3
And voilà!
p.s. in Table 1.0, Vacant2 and Comblé2 are a percentage of the ratio of each calculated member over the sum of the two.

Sorting/Ordering sequenced pairs of data in MySQL?

I am trying to determine if there's a way to sort rows of a MySQL table that consists of start/finish columns. (Could also be thought of as parent/child relations or other linked list arrangement)
Here's an example of how the data is currently stored:
id start finish
2 stepthree stepfour
6 stepfive stepsix
9 stepone steptwo
78 stepfour stepfive
121 steptwo stepthree
(The id numbers in this are not relevant, just using them to indicate additional columns of arbitrary data)
I want to sort/display these row in order, presuming I am always starting with "stepone", that traverses the start-> finish chain like, each "finish" being followed by the row with it as a "start".
desired output
9 stepone steptwo
121 steptwo stepthree
2 stepthree stepfour
78 stepfour stepfive
6 stepfive stepsix
There shouldn't be any branching/splits normally, just a sequential series of steps or states. I can't use simple alpha sorting (in my case the start and finish values are codes created by a customer), but can't figure out any other way to order these using SQL. I could programmatically do it using most languages, but stumped about doing it just with SQL.
Any clever ideas?
I would recommend having another table that has each step mapped to its precedence order.
Then you can write a query to sort each row in the order of precedence of the start step.

MySQL ORDER BY CASE / IF relevance issue

I've never worked with ORDER BY CASE or ORDER BY IF() and the few examples I've found on the internet are more confusing than helping me trying to accomplish following task:
I have a member list and I want to "reward" the user's activity a bit by ordering a user higher (to the top) in this member list.
In my example, I have a MySQL table called "users" with 3 columns:
user_percentage | user_photo | user_lastlogin
----------------------------------------------------------
12 1 1356389646
42 1 1456549641
37 0 1776389443
84 1 1356535535
56 0 1868689646
66 0 1811189622
71 1 1656779645
"user_percentage" holds the value (0 - 100) of all filled in profile
fields by each user.
"user_photo" holds the value (0 = false , 1 =
true) if a user has upload a profile photo.
"user_lastlogin holds the
value (timestamp) of their last visit.
It's a bit difficult to explain, but to say it simple what I want:
A user with a higher user_percentage value should be on top of the member list, but if he got no user_photo, then he should be "moved down" in the member list, same if he got an old user_lastlogin timestamp, then list him even more down in the member order.
Also what I'm trying to prevent is that a user has signed up, filled in all profile fields (then user_percentage value will be = 100) and uploaded a photo (then user_photo will be = 1), but hasn't login anymore since a long time (so he has a very old user_lastlogin = timestamp), then I want this user moved down in the member list order.
My question is: Is this somehow possible to do with 1 MySQL ORDER BY statement?
Let's say user_photo has just an importance of 30% while user_lastlogin got a higher importance and user_percentage also a bit higher.
Any ideas?
Best regards!
In order to even begin writing the SQL, you need to clarify how much each parameter is worth.
You should produce a list of examples and then convert it into either a simple calculation like:
(photo*timesincelogin*20)+(percentage)
or CASE based statements which each have a calculation - i.e:
ALL people with photos THEN ALL people with out, subsorted by time*percentage.
Hand-wavy 'move down a bit' is not specific enough for an answer with SQL commands.