Power BI report Builder - Divide overflowing matrix row - reporting-services

I have a dynamic row of attributes associated with customer. Number of attributes for each customer may vary from 3 to n.
I am trying to display it in a row but if number of attributes increase from 3 to 10 data over flows from right to left on a page. For example
Attribute 1 | Attribute 2 | Attribute 3 | Attribute 4 | Attribute 5 | Attribute 6 | Attribute 7
Is it possible to start a new row for attributes after fixed number of columns, lets say 4?
Attribute 1 | Attribute 2 | Attribute 3 | Attribute 4
Attribute 5 | Attribute 6 | Attribute 7
I found similar question Table not overflowing properly - Power BI Report Builder but steps mentioned in answer are not clear.
Edit:
Design view:
Report View
TEST
I tried adding colum/row groups but doing that creates a matrix like this
Desired View
first 4 attributes to be rendered on 1st row and next 3 attributes to be rendered on second row

The way I would normally do something like this is to calculate the row and column numbers in the dataset query, then you can use these values as the row and column groups.
The following query creates some sample data, just ID and Attribute and then returns that same data along side the RowN and ColN columns which hold the row and column numbers respectively.
I've also parameterised this so you can easily adjust the number of generated columns.
The sample data contains data for 3 unique IDs, each with a different number of attributes.
Note: the attributes are named such they can be ordered alphabetically, you may have to adjust the three instances of the ORDER BY clause to get the order correct with your real data (if it matters).
DECLARE #t TABLE (ID int, Attribute varchar(20))
INSERT INTO #t VALUES
(1, 'Attribute 01'), (1, 'Attribute 02'), (1, 'Attribute 03'),
(2, 'Attribute 01'), (2, 'Attribute 02'), (2, 'Attribute 03'), (2, 'Attribute 04'), (2, 'Attribute 05'),
(3, 'Attribute 01'), (3, 'Attribute 02'), (3, 'Attribute 03'), (3, 'Attribute 04'), (3, 'Attribute 05'), (3, 'Attribute 06'), (3, 'Attribute 07'), (3, 'Attribute 08'), (3, 'Attribute 09'), (3, 'Attribute 10'), (3, 'Attribute 11')
DECLARE #MaxCols int = 5
SELECT
ID, Attribute,
RowN = (ROW_NUMBER() OVER(PARTITION BY ID ORDER BY Attribute)-1) / #MaxCols,
ColN = (ROW_NUMBER() OVER(PARTITION BY ID ORDER BY Attribute)-1) - (((ROW_NUMBER() OVER(PARTITION BY ID ORDER BY Attribute)-1) / #MaxCols) * #MaxCols)
FROM #t
This gives us the following results (clipped for brevity)
Now we can create a simple matrix as per the design below. (Note the two row groups and one column group)
You can remove the RowN column (but not the group), I left it in for clarity..
When we run the report using 5 as the #MaxCols value we get this..
and settings the #MaxCols value to 4 gives us this.

Related

SSRS Show table list in sequence

I have a list of data, with sequence id 1, 2, 3, ..., 9
I want to insert them into SSRS report in the form of 3x3 table, arranged by sequence id
1 2 3
4 5 6
7 8 9
I should use list, or table, or matrix? Any solution for this arrangement? Thanks
I would typically use a matrix for this. You can calculate the row and column numbers for each row of data in your table and then use that for your row and column groups in the matrix.
Here's an example...
Note: You might not have or want the 'label' field so just swap this out for whichever field you want to show when we get to the report design.
Here's some sample data with the Row and Col calculated
DECLARE #t TABLE (Seq int, Label varchar(10))
INSERT INTO #t VALUES
(1, 'AAAAA'), (5, 'BBBBB'), (10, 'CCCCC'),
(20, 'DDDDD'), (50, 'EEEEE'), (100, 'FFFFF'),
(101, 'GGGGG'), (102, 'HHHHH'), (210, 'IIIII')
SELECT
*
, ColN = (SeqOrder-1) %3
, RowN = (SeqOrder-1) / 3
FROM (SELECT *, ROW_NUMBER() OVER(ORDER BY Seq) AS SeqOrder FROM #t) t
The inner query just assigns the SeqOrder as 1 thru 9. We then use this SeqOrder value to determine the row and column
This gives us the following dataset
Then we just add a matrix to our report
Next, drag the ColN field to the "Columns" placeholder, the RowN field to the "Rows" placeholder and the Label field (or whatever field you want to display) to the "Data" placeholder.
Run the report and you get this
Optionally, you can remove the first row and column (but NOT the associated group) and just leave the data cell.
Now when we run it, we get this.

SSRS - Lookup only on certain columns in a matrix

I have a matrix table with a column group "Application questions" let's say these are in table 1. Some of the questions have unique string values such as: Name, ID number, email address. But others have an integer value that relates to an actual value for a separate lookup table (table 2), for example, the values for the column "Gender" are 1, 2, 3, for Male, Female, Other. Is there a way in the lookup function that I can isolate the columns that only have integer values or alternatively ignore the other columns with unique string values?
Table1
NAME ATTRIBUTE_id ATTRIBUTE
-----------------------------------------
James 5 1
James 6 james#email.com
James 7 8
Table2
Lookup_id ATTRIBUTE_id Description
-----------------------------------------
1 5 Male
2 5 Female
3 5 Other
8 7 New York
9 7 Los Angeles
Output
NAME | Email | Gender | City
-------------------------------------------------------
James james#email.com Male New York
Hope that makes sense!
Thank you.
I think this will be easier to do in your dataset query.
Below I have recreated your sample data and added an extra person in to make sure it's working as expected.
DECLARE #t TABLE (Name varchar(10), AttributeID INT, AttributeMemberID varchar(50))
INSERT INTO #t VALUES
('Mary', 5, '2'),
('Mary', 6, 'Mary#email.com'),
('James', 5, '1'),
('James', 6, 'james#email.com'),
('James', 7, '8')
DECLARE #AttributeMembers TABLE (AttributeMemberID INT, AttributeID int, Description varchar(20))
INSERT INTO #AttributeMembers VALUES
(1, 5, 'Male'),
(2, 5, 'Female'),
(3, 5, 'Other'),
(8, 7, 'New York'),
(9, 7, 'Los Angeles')
I also added in a new table which describes what each attribute is. We will use the output from this as column headers in the final SSRS matrix.
DECLARE #Attributes TABLE(AttributeID int, Caption varchar(50))
INSERT INTO #Attributes VALUES
(5, 'Gender'),
(6, 'Email'),
(7, 'City')
Finally we join all three togther and get a fairly normalised view for the data. The join is a bit messy as your current tables use the same column for both integer based lookups/joins and absolute string values. Hence the CASE in the JOIN
SELECT
t.Name,
a.Caption,
ISNULL(am.[Description], t.AttributeMemberID) as Label
FROM #t t
JOIN #Attributes a on t.AttributeID = a.AttributeID
LEFT JOIN #AttributeMembers am
on t.AttributeID = am.AttributeID
and
CAST(CASE WHEN ISNUMERIC(t.AttributeMemberID) = 0 THEN 0 ELSE t.AttributeMemberID END as int)
= am.AttributeMemberID
ORDER BY Name, Caption, Label
This gives us the following output...
As you can see, this will be easy to put into a Matrix control in SSRS.
Row group by Name, Column Group by Captionand data cell would beLabel`.
If you wanted to ensure the order of the columns, you could extend the Attributes table to include a SortOrder column, include this in the query output and use this in SSRS to order the columns by.
Hope that's clear enough.

SSRS - avg function by subtotals

I have details, subtotals and totals.
When I put avg function in totals line I have avg of every row.
I need avg of subtotals
How to do it?
week1
day1..... 2
day3..... 3
day4..... 4
day6..... 2
total.... 11 sum()
week2
day1..... 3
day2..... 2
total..... 5 sum()
Total
........... 16 sum() OK
............ 2,66666 avg() here should be (11+5)/2 =8
Result after implementing solution
I created a dataset to replicate your sample data as follows:
DECLARE #t TABLE (week int, day int, amount int)
INSERT INTO #t VALUES
(1, 1, 2),
(1, 3, 3),
(1, 4, 4),
(1, 6, 2),
(2, 1, 3),
(2, 2, 2)
SELECT * FROM #t
I then built a simple tablix as you had done (more or less)
I included the incorrect results you had for illustration and then added a new expression to calculate this correctly.
The result looks like this
You can ignore the other datasets, this is just a report I use for testing. Only dataset3 is used here.
The expression used was this
=Sum(Fields!amount.Value) / CountDistinct(Fields!week.Value)
You'll just need to edit this to match your field names. It basically just sums all the detail amounts then divides by the number of distinct weeks in the dataset.

SQL Query for exact match in many to many relation

I have the following tables(only listing the required attributes)
medicine (id, name),
generic (id, name),
med_gen (med_id references medicine(id),gen_id references generic(id), potency)
Sample Data
medicine
(1, 'Crocin')
(2, 'Stamlo')
(3, 'NT Kuf')
generic
(1, 'Hexachlorodine')
(2, 'Methyl Benzoate')
med_gen
(1, 1, '100mg')
(1, 2, '50ml')
(2, 1, '100mg')
(2, 2, '60ml')
(3, 1, '100mg')
(3, 2, '50ml')
I want all the medicines which are equivalent to a given medicine. Those medicines are equivalent to each other that have same generic as well as same potency. In the above sample data, all the three have same generics, but only 1 and three also have same potency for the corresponding generics. So 1 and 3 are equivalent medicines.
I want to find out equivalent medicines given a medicine id.
NOTE : One medicine may have any number of generics. Medicine table has around 102000 records, generic table around 2200 and potency table around 200000 records. So performance is a key point.
NOTE 2 : The database used in MySQL.
One way to do it in MySQL is to leverage GROUP_CONCAT() function
SELECT g.med_id
FROM
(
SELECT med_id, GROUP_CONCAT(gen_id ORDER BY gen_id) gen_id, GROUP_CONCAT(potency ORDER BY potency) potency
FROM med_gen
WHERE med_id = 1 -- here 1 is med_id for which you're trying to find analogs
) o JOIN
(
SELECT med_id, GROUP_CONCAT(gen_id ORDER BY gen_id) gen_id, GROUP_CONCAT(potency ORDER BY potency) potency
FROM med_gen
WHERE med_id <> 1 -- here 1 is med_id for which you're trying to find analogs
GROUP BY med_id
) g
ON o.gen_id = g.gen_id
AND o.potency = g.potency
Output:
| MED_ID |
|--------|
| 3 |
Here is SQLFiddle demo

Query to get categorised sets of splits

Given this table structure:
CREATE TABLE IF NOT EXISTS splits (
id INT AUTO_INCREMENT,
sector_id INT,
type VARCHAR(100),
percentage INT,
PRIMARY KEY (id),
INDEX (type)
) ENGINE MyISAM;
And this data set:
INSERT INTO splits (sector_id, type, percentage) VALUES
(1, 'Manager', '50'),
(1, 'Sales Rep', '50'),
(2, 'Manager', '75'),
(2, 'Sales Rep', '25'),
(3, 'Manager', '75'),
(3, 'Sales Rep', '25'),
(4, 'Manager', '100'),
(5, 'Manager', '100'),
(6, 'Manager', '100');
How could I return the amount of sectors that split in the same way:
Like this:
Split | Number
---------------+-------
50% M / 50% SR | 1
75% M / 25% SR | 2
100% M | 3
So this shows 1 sector (id 1) has a split ratio of 50/50, 2 sectors have a split ratio of 75/25 (ids 2, 3) and 3 sectors have a split ratio off 100/0 (ids 4, 5, 6).
Here is a SQL Fiddle with the database setup: http://sqlfiddle.com/#!2/6b19f/1
What have you tried?
I cannot even think of where to start to solve this problem, so I apologise for not being able to show an attempted solution. I will update this question if I get anywhere.
The reason why I want to do this all in the database (and not the application) is because our automated reporting tools can be pointed to a table/view/query and automatically apply filtering, sorting, charting etc. To do it manually in the application loses all the default functionality.
I don't really understand the problem. Your DB contains already all the data you want to retrieve?!
SELECT
sector_id AS Number,
type
percentage
FROM
splits
The easiest thing would now to take you software and then turn those (type-percentage)-tuples into strings. Why do you need the database to create and concat this string?
Can there be more than 2 types?
For Postgres I'd use an array of tuples for output:
SELECT
sector_id,
array_agg(row(percentage, type))
FROM
splits
GROUP BY
sector_id
Correct Query:
SELECT
x.y,
COUNT(*) c
FROM (
SELECT
sector_id,
GROUP_CONCAT(CONCAT(percentage, '% '), type SEPARATOR ' / ') AS y
FROM (
SELECT
sector_id,
type,
percentage
FROM splits
ORDER BY sector_id, type
) z
GROUP BY sector_id
) x
GROUP BY x.y
ORDER by c
Result will look like this:
50% Manager / 50% Sales Rep | 1
75% Manager / 25% Sales Rep | 2
100% Manager | 3