SSRS report with many-to-many tables in sub-tablix - reporting-services

I have a main table (Table A). It has separate many-to-many relationships to two other tables (Table B and Table C).
I would like to create an SSRS report that has one row per record in Table A, but then displays a sub-table for each Table B and Table C in one of the columns.
I believe that I can do this by creating a sub-report for Table B and Table C, by passing the Table A ID to each of the two sub-reports. However, I'm wondering if this is possible to do without creating sub-reports.
Below is an example of the data structure and what I would like the report to look like.

This is a little long winded as I didn't have any sample data to work with. I created come sample data as follows.
CREATE TABLE TableA(aID int, a1 varchar(20), a2 varchar(20))
GO
CREATE TABLE TableB(bID int, b1 varchar(20), b2 varchar(20))
GO
CREATE TABLE TableC(cID int, c1 varchar(20), c2 varchar(20))
GO
INSERT INTO TableA VALUES (1,'Red', 'Green'), (2,'Blue', 'Purple')
INSERT INTO TableB VALUES (1,'Dave', 'Bob'), (1,'Geoff', 'Harry'), (2,'Jane', 'Mary'), (2,'Anne', 'Sue')
INSERT INTO TableC VALUES (1,'Dog', 'Cat'), (2,'Goat', 'Cow'), (2,'Sheep', 'Lamb'), (2,'Donkey', 'Horse'), (2,'Lizard', 'Frog')
I then created a query that joins the tables together, it includes a 'TableName' column to indicate which table it came from, we will use this to arrange the columns in a matrix. It also contains a row number for each row per table. The query looks like this.
SELECT
*
, RowN = ROW_NUMBER() OVER(PARTITION BY aID, TableName ORDER BY ID, FirstColumn, SecondColumn)
FROM (
SELECT
a.*
, 'Table B' as TableName
, bID as ID, b1 as FirstColumn, b2 as SecondColumn
FROM TableA a
JOIN TableB b on a.aID = b.bID
UNION ALL
SELECT
a.*
, 'Table C' as TableName
, c.*
FROM TableA a
JOIN TableC c on a.aID = c.cID
) u
In the port designer, I added a matrix control. I set the row groups to group by aID and Rown and added a column group by TableName .
Finally I set the first three columns Hide duplicates property to DataSet1
The report design looks like this..
The final output looks like this...
It's not perfect but it should be enough to get you going.

Related

Can you link a column in one table which has column names of another table with that second table

I have two tables A and B
Table A has a list of all columns in table B
Table B has values in each column
In MS Access, is it possible to create a query linking the values in the column in Table A with the Columns in Table B?
The SELECT statement I am thinking of is something along the lines of:
SELECT A.Col1,A.Col2,B.Col1,B.Col2
FROM TableA AS A
LEFT OUTER JOIN TableB AS B
-- this is where I get stuck but in pseudo-code might be ..
ON value in A.Col3 = B.Col3
Thanks for any help on this even if it's "No, this can't be done in Access"
TableB is not normalized data structure. It has no relationship with TableA and join is not possible nor does it make sense. Do a UNION query on TableB to reorganize data to normalized structure.
I presume TableB has a unique identifier field.
SELECT ID, "SourceOfReferrals_SQ001" AS Source, SourceOfReferrals_SQ001 AS Data FROM TableB
UNION SELECT ID, "SourceOfReferrals_SQ002", SourceOfReferrals_SQ002 FROM TableB
UNION SELECT ID, "SourceOfReferrals_SQ003", SourceOfReferrals_SQ003 FROM TableB
UNION SELECT ID, "SourceOfReferrals_SQ004", SourceOfReferrals_SQ004 FROM TableB
UNION SELECT ID, "SourceOfReferrals_SQ005", SourceOfReferrals_SQ005 FROM TableB;
Now this query can be joined to TableA if there are other fields in TableA you want data from.
Alternative is VBA looping fields of recordset to write data to a normalized table.

Create view to get values from multiple tables

I thought it is easier to edit this post and give exact example what I meant by that post after all.
Main idea is that I need to get values from different tables.
Basically main idea is to select all values from Table B and Table C, but
selecting only values from Table C which are not present in Table B (but at the same time I need to
left join Table C to get text column value).
Table B and Table C has similar structure. They both have ref_num (ID) and text value.
Also Table B holds Table C ref_num, because when Table C entity is modified ("modifiable_column"),
then record is saved into Table B, but "default" value text column is taken from Table C.
It's something like.
Let's say we have default rules (Table C - always same values forever), then we have custom rules (Table B). Table D holds version of each rule with current as end_date IS NULL. Default values have default "modifiable_column" as 'N' as mentioned before. Now, let's say I take one rule from Table C and change "modifiable_column" to 'Y'. Then new row is created into Table B (with ref_num, table_c_ref_num, text = NULL). It means that this rule is now custom for this particular TabelA ref_num, at the same time new row is inserted into Table D (holding new row ref_num as table_b_ref_num and new "modifiable_column" value).
Now, when I want to select custom rules, default rules and versions (end_date IS NULL). I have to join Table B, Table C and Table D. But as Table C has always same rules, I only need to join it to get the text value. And I have to make sure I won't select duplicates. Meaning if Table C has 10 default rules, now one was modified and custom rules (Table B) has 1 rule. Then I have to so said select 1 from Table B and 9 from Table C, but at the same time I need to join Table C text value for this custom rule.
I have following tables as below:
create table TableA (
ref_num INT
);
create table TableB (
ref_num INT,
text VARCHAR(100),
table_c_ref_num INT,
table_a_ref_num INT
);
create table TableC (
ref_num INT,
text VARCHAR(100)
);
create table TableD (
ref_num INT,
table_b_ref_num INT,
modfifable_column VARCHAR(1),
start_date date,
end_date date
);
Inserting initial values as below:
insert into TableA (ref_num) values (1);
insert into TableC (ref_num, text) values
(1, "Text 1"),
(2, "Text 2"),
(3, "Text 3");
insert into TableB (ref_num, text, table_c_ref_num, table_a_ref_num) values
(1, NULL, 2, 1);
insert into TableD (ref_num, table_b_ref_num, modfifable_column, start_date, end_date) values
(1, 1, 'Y', now(), NULL);
Now I have created this select statement to get wanted behaviour:
SELECT * FROM (
SELECT
tb.ref_num AS ref_num,
tb.table_a_ref_num AS table_a_ref_num,
coalesce(tc.text, tb.text),
coalesce(tc.ref_num, tb.table_c_ref_num) AS table_c_ref_num,
coalesce(td.modfifable_column, 'N') AS modfifable_column
FROM TableB tb
LEFT JOIN TableD td on td.table_b_ref_num = tb.ref_num AND td.end_date IS NULL
LEFT JOIN TableC tc on tc.ref_num = tb.table_c_ref_num
WHERE tb.table_a_ref_num = 1
) as cust
UNION ALL
SELECT * FROM (
SELECT
NULL AS ref_num,
NULL AS table_a_ref_num,
tc2.text AS text,
tc2.ref_num AS table_c_ref_num,
'N' AS modfifable_column
FROM TableC tc2
WHERE tc2.ref_num NOT IN (
SELECT
tb2.table_c_ref_num
FROM TableB tb2
LEFT JOIN TableD td on td.table_b_ref_num = tb2.ref_num AND td.end_date IS NULL
LEFT JOIN TableC tc on tc.ref_num = tb2.table_c_ref_num
WHERE tb2.table_a_ref_num = 1
)
) as def;
I know that I can turn those two inner SELECT statements into views and then combine them with UNION ALL for example. My biggest concern here is that I have to "hard code" table_a_ref_num = 1 into two different places.
Because I have to use TableA ref_num in order to get custom values from TableB and default values from TableC. Because at the end TableA ref_num is like “this specific” entity custom rules and default rules.
My question is: Is there a way to wrap my big SELECT clause into one view, where I could use this TableA ref_num value to get results as in my example.
I don't fully understand your tables and pseudo code, but based on this limited understanding, my suggestion would be that you start with a query similar to this on:
select 'ta',ta.*,'tb',tb.*,'tc_via_b',tc_via_b.*,'tc_via_a',tc_via_a.*,'td',td.*
from table_a ta
left join table_b tb on tb.table_a_ref_num = ta.ref_num
left join table_c tc_via_b on tc_via_b.ref_num = tb.table_c_ref_num
left join table_c tc_via_a on tc_via_a.ref_num = ta.ref_num
left join table_d td on td.table_b_ref_num = tb.ref_num AND td.end_date IS NULL;
This way you will see all lines you want as a first step. In a second step, you should be able to use NVL and CASE to get the data you want. HTH

join table A first row with table B first row without common identifiers (for all rows) . Mysql

I messed up with identifiers and my two tables can't be joined by any column. But their order is the same. First row in table A is first row in table B, second row in table A is second row in table B and the same with rest. Is there any way to join those two tables by their row number or something like that?
For example:
Table A:
two
three
one
Table B:
cat
dog
mouse
Expected result would be:
two - cat
three - dog
one - mouse
Or is it not possible and I need to start everything all over again ?
You could add an auto increment column to each table:
ALTER TABLE TableA ADD COLUMN (id INT AUTO_INCREMENT PRIMARY KEY);
ALTER TABLE TableB ADD COLUMN (id INT AUTO_INCREMENT PRIMARY KEY);
Then you can do a join
SELECT num, animal
FROM TableA
JOIN TableB ON TableA.id = TableB.id
Output:
num animal
two cat
three dog
one mouse
Use the query
select a.c1, b.c1
from
(select c1 ,#rownum:=#rownum+1 as rn1 from taba,(SELECT #rownum:=0) r ) a
join
(select c1 ,#rownum1:=#rownum1+1 as rn2 from tabb,(SELECT #rownum1:=0) s ) b
on a.rn1 = b.rn2
SQL Fiddle :- http://sqlfiddle.com/#!9/a046b5/22

Returning most recent row in table from a join

I have two tables. Consider them Table A and Table B.
Table A has a list of things in it.
Table B might have entries which point back to the things in Table A.
That is to say, for every row in Table A, there may be 0 rows or n rows in Table B that link back to it (via some ID column also in Table B).
What I want to do is run 1 SELECT statement with some kind of JOIN which returns a list of all the rows from Table A (all columns) and 1 column from Table B where that 1 column from Table B is ordered DESC (the column is a timestamp, and I want the most recent timestamp).
That is to say, I want my SELECT statement to return 1 row for each row in Table A. One of the columns in the result set will be data from Table B, and it has to grab the data from the most recent entry corresponding to the Table A row.
I'm really at a loss on how to do this. I've even tried adding "TableB.created_on = max(TableB.created_on)" to the ON clause of the JOIN.
Assuming sample schema looks like
CREATE TABLE a
(id INT, description VARCHAR(64));
CREATE TABLE b
(id INT, timestamp timestamp);
You can do
SELECT *,
(SELECT MAX(timestamp)
FROM b
WHERE id = a.id) max_timestamp
FROM a
or
SELECT a.id, a.description, MAX(b.timestamp)
FROM a JOIN b
ON a.id = b.id
GROUP BY a.id, a.description
SQLFiddle (for both queries)

Relational Tables - Select Only Rows in Table A That Don't Exist as ID in Table B

I have table A that stores courses and table B that stores current progress of users.
table A has unique ID column for each course (courseID) which also exists in table B with the same name (thus their relation).
I want to get all rows from table A whose IDs don't exist in table B. (e.g. no user has currently entered this course)
The two tables don't use foreign keys, just a column with the same name.
TRY
SELECT A.* FROM tableA A
LEFT JOIN tableB B ON USING (courseID)
WHERE B.courseID IS NULL
SELECT * FROM A WHERE A.courseID NOT IN (SELECT courseID FROM B);
You need LEFT JOIN
SELECT * FROM `tableA`
LEFT JOIN `tableB` ON `tableA`.`ID`=`tableB`.`ID`
WHERE `tableB`.`ID` IS NULL;
What database are you using?
If you're using Oracle, I think you want:
select A.student_code from A where not exists
( select 'x' from B where B.student_code = A.student_code)
At least that's what I think you were asking for..