RDLC report - Duplicate data issue in grouping - reporting-services

I have a RDLC report in which I want grouping by username and status which has value open and closed. I am getting duplicate username when both the value of status is present for the username.
In the expression, I have used below code -
=IIf (
Fields!Status.Value.ToString().ToLower().Trim() = "open",
Count(Fields!Status.Value),
0 )
=IIf (
Fields!Status.Value.ToString().ToLower().Trim() = "closed",
Count(Fields!Status.Value),
0)
My output is this one - Current Output
And I want this output - Required Output

I would simply use a matrix instead of a table.
You can then have a rowgroup by Username, a column group by Status and then the value would simple be =CountRows()
So, using your sample data as my dataset query.
declare #t table (UserName varchar(10), [Status] varchar(10))
INSERT INTO #t VALUES
('User1', 'Closed'),
('User2', 'Closed'),
('User3', 'Closed'),
('User3', 'Closed'),
('User3', 'Closed'),
('User3', 'Closed'),
('User3', 'Closed'),
('User3', 'Closed'),
('User4', 'Closed'),
('User4', 'Closed'),
('User4', 'Closed'),
('User4', 'Open')
select * from #t
Create a new report and add a matrix control.
Drag the fields to the respective column and rows headers as shown below.
Next, set the Value cell's expression to =CountRows()
This will give us a basic matrix output.
Next to add the totals...
In the row and column group panel below the main design window, right-click the group, then select "add total" then "After", repeat this for both row and column groups.
Set the expression for the new cells to, again, =CountRows()
The final design looks like this.
(note all the cells that show expression are set the the same =CountRows() expression.)
The final output looks like this (after a bit of bold and shading)

Related

MySQL Can I split the group further if need it after using group by method based on the grouping condition

So I hope I can explain my question clear
I wonder if there is a way to further split the grouping if need it based on the grouping condition
create Table if NOT EXISTS click_action (
cid int(3) NOT NULL,
session_id int(5) NOT NULL,
click_val int NOT NULL,
PRIMARY KEY(cid)
);
INSERT INTO click_action (cid, session_id, click_val)
VALUES (111, 12345, 2),
(121, 12345, 3),
(131, 12345, 4),
(141, 12344, 2),
(151, 12344, 3),
(161, 12344, 8),
(171, 12344, 9)
Above I set a small table with a cid, session id, click_val and use cid as a primary key. I insert some test value under the create table statement. I want to generate a query which will group by session id and return a randomly generated session grouping id, the max click val and min click val in the grouping. However after group by session id. I want to make sure there isn't a huge gap greater than 3 between the sorted click val value in each grouping. If there is, we split between the gap.
So for example given the test value I inserted. If we first group by session_id, we can get first group which has cid 111, 121, and 131. If we check the click_val in the group which is value 3,4 and 5, we find there is no gap larger than 3 so this grouping is accepted. However in second grouping using session id 12344, we can group together with cid value of 141, 151, 161 and 171. However if we want to check the gap, we first sort based on click val, which we get 2, 3, 8, 9. Then we can find out there is a larger than 3 click val gap between value 3 and 8. So when that happen I want my query to split this group into cid 141, 151 and another group with cid 161,171
The final query that will return should be
random id, 3, 4
random id, 2, 3
random id, 8, 9
I been stuck on this problem on some time now, I was wondering how can I do this or is there any build in SQL function I am not aware of that can help me solve the task?
WITH
cte1 AS ( SELECT cid, session_id, click_val,
(click_val - COALESCE(LAG(click_val) OVER (PARTITION BY session_id ORDER BY cid), -3)) > 3 too_wide
FROM click_action ),
cte2 AS ( SELECT cid, session_id, click_val,
SUM(too_wide) OVER (ORDER BY session_id, cid) random_id
FROM cte1 )
SELECT random_id, session_id, MIN(click_val), MAX(click_val)
FROM cte2
GROUP BY random_id, session_id;
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=5f6f80320bf630881869c1cee733d2b3
If you want to have really random random_id values then generate them additionally checking their uniqueness.

How to merge and center for certain row in SQL/SSRS report?

I have a table as below:
I'd like to merge and center S/No 1.0 and 2.0 only, and display to SSRS report, the rest of the row remained unchanged, is there a way to do it?
The result will be like the 2nd image below.
Method 1: No real changes to dataset.
Add a parent row group with a header to your current tablix. Set the grouping to an expression such as (assuming S/No is from a field called SerialNumber
=CINT(Fields.SerialNumber.Value)
So here we just convert S/No to an integer so 1.0 and 1.1 both return 1
Now you will have a header row for each group of rows.
You can merge the cells in the header row and set the expression to
=FIRST(Fields!Description.Value)
You may have to force the order of the data in your dataset to ensure that 1.0 is always before 1.1 etc.
Method 2: Add the group names to your dataset
Note: This is written for SQL Server not MySQL but should be easy enough to translate if required
If this does not work then you could add the group headers into a new column in your dataset query, then just group on that. The dataset query would look something like this...
(I've replicated your data to show it working)
DECLARE #myTable TABLE (SerialNumber decimal (5,1), Description varchar(50), UOM varchar(50), rate decimal (10,2))
INSERT INTO #myTable VALUES
(1.0, 'Warehouse Charges', NULL, NULL),
(1.1, 'Storage in pallet', 'perpallet per month or part thereof', 15.84),
(2.0, 'Handling', NULL, NULL),
(2.1, 'Unstuffing - Palletised', 'per pallet', 5.00),
(2.2, 'De-palletised', 'per palett', 5.00)
SELECT * FROM #myTable
SELECT
b.Description as GroupName, a.*
FROM #myTable a
JOIN (SELECT SerialNumber, Description FROM #myTable WHERE CAST(SerialNumber AS INT) = SerialNumber) b -- headers only
ON CAST(a.SerialNumber AS INT) = b.SerialNumber
WHERE a.SerialNumber != b.SerialNumber
This produces the following output
So now you can just group on the groupname field and then merge as described in the earlier method.

sql select multiple rows based on conditions of two or more columns

I am trying to select multiple rows based on 3 columns matching particular criteria. For a single search I do the following:
SELECT user_id
FROM users_to_users
WHERE user_id = '1' AND contact_user_id = '9' AND contact_blocked = 1
I would like to submit a set of values to return multiple rows.
so my values would be as such:
('1', '9', 1), ('2, '9', 1),('3', '9', 1) etc...
And return user_id's for the rows which match. In essence I'm trying to see which users have blocked user '9' so that I could then add only the users that are not blocked to the next statement.
Being very unfamiliar with SQL what I thought might work was the following:
SELECT user_id
FROM users_to_users
WHERE (user_id, contact_user_id, contact_blocked) VALUES (...)
But unable to do that. Is there any way to select multiple rows based on matching conditions for multiple columns?
Are you trying to use tuples with in? If so, this works:
SELECT user_id
FROM users_to_users
WHERE (user_id, contact_user_id, contact_blocked) in ( (1, 9, 1), (2, 9, 1), (3, 9, 1) )
There may be other ways, however, to accomplish your ultimate goal.

SQL Query - Duplicate data more than once based on values assigned

I am trying to duplicate/copy data from "product" table and add new values in "carrier" column.
Example:
In "product" table, I have a list of products which I will need to assign with another table, "carrier". There are currently 5 carriers in "carrier" table.
In "product_carrier" table, I would like to create new entries here. Product "sample-1" is assigned to carrier 1, 2, 3 and 4. Product "sample-2" is assigned to carrier 5.
Thus, it becomes as such:
sample-1 | 1
sample-1 | 2
sample-1 | 3
sample-1 | 4
sample-2 | 5
This is the database structure of the e-commerce system that I am currently using to assign carriers.
My tables are -
ps_product: id_product
ps_carrier: id_carrier
ps_product_carrier: id_product, id_carrier_reference
My hunch is that, I will need to update 2 set of data groups. Firstly, products set to carrier (1, 2, 3, 4) and another set of products to assign to carrier (5). I will run 2 set of queries to achieve this.
I have no clue as to execute a duplicate of a product and create insert multiple values for different carriers. Currently, I have thousands of products that need to be assigned accordingly.
I have no idea if this is possible and that if you have any advice, that will be truly appreciated.
Thank you.
Assuming you have a table named table_with_product_list (or a list) when you assign all the product you want assign to a carrier
you can use a insert select
eg for multiple carrier (1,2,3,4)
insert into ps_product_reference (id_product, id_carrier_reference)
select table_with_product_list.product_id, t.id_carrier
from table_with_product_list
cross join (
select id_carrier from ps_carrier
where id_carrier in ( 1,2,3,4)
) t
for single carrier (5)
insert into ps_product_reference (id_product, id_carrier_reference)
select table_with_product_list.product_id , 5
from table_with_product_list
As there is nothing in the database to indicate whether a product shall be combined with carriers 1 to 4 or with carrier 5, you'll have to state them yourself. In my opinion there is nothing that speaks against two separate INSERT statements. You can use a text editor or Excel maybe or a programm you quickly write yourself to build the VALUES clause:
insert into ps_product_carrier (id_product, id_carrier_reference)
values
(1111, 1),
(1111, 2),
(1111, 3),
(1111, 4),
(3333, 1),
(3333, 2),
(3333, 3),
(2222, 4),
... ;
commit;
insert into ps_product_carrier (id_product, id_carrier_reference)
values
(2222, 5),
(4444, 5),
... ;
commit;
Or start with the second statement above and then instead of the first query use:
insert into ps_product_carrier (id_product, id_carrier_reference)
select p.id_product, c.id_carrier
from ps_product p
cross join (select id_carrier from ps_carrier where id_carrier in (1,2,3,4)) c
where p.id_product not in
(select id_product from ps_product_carrier where id_carrier_reference = 5);

How to add parameter to aggregate function in report dataset

Thank you for coming to look at my question.
I have an SQL group by function which I'd like to add parameters to. (If that's possible)
I've tried to splice the parameters, two columns from the table into the function but I don't seem to get it right.
This function creates a table that counts records, I would like to be able to filter with parameters by 'Team' and 'Location'.
How would I go about adding this information to the dataset to allow me to filter?
I would normally add them using:
select
i.Team
,i.Location
From
incident i
Where i.Team in (#Team)
and i.Location in (#Location)
The table is called incident and all the information is from the same table.
I would very much appreciate an idea to do this. Thank you.
Oh, and I'm using Report Builder 3, with SQL 2008 R2
declare #st_date datetime;
declare #en_date datetime;
declare #days int;
declare #offset int;
set #en_date = (#en_datein);
set #offset = (#BrowserTimezoneOffset);
set #days = -6;
set #st_date = DATEADD(dd, #days, #en_date);
with daterange(dt) as
(select
#st_date dt
union all
select
DATEADD(dd, 1, dt) dt
from daterange
where dt <= DATEADD(dd, -1, #en_date)
)
select
left(DATENAME(dw, dt), 3) as weekday
,ISNULL(sum(inc.createdc), 0) as createdcount
,ISNULL(sum(inr.resolvedclosedc), 0) as resolvedclosedcount
from daterange left outer join
(select
left(DATENAME(dw,DATEADD(mi,#offset,CreatedDateTime)), 3) as createddatetime
,count(recid) as createdc
from Incident
where DATEADD(mi,#offset,CreatedDateTime) >= #st_date
and DATEADD(mi,#offset,CreatedDateTime) <= #en_date
group by left(DATENAME(dw, DATEADD(mi,#offset,CreatedDateTime)), 3)
) as inc
on inc.CreatedDateTime = left(DATENAME(dw, dt), 3)
left outer join
(select
left(DATENAME(dw, DATEADD(mi,#offset,ResolvedDateTime)), 3) as ResolvedDateTime
,count(case when status in ('Resolved', 'Closed') then 1 end) as resolvedclosedc
from Incident
where DATEADD(mi,#offset,ResolvedDateTime) between #st_date and #en_date
group by left(DATENAME(dw, DATEADD(mi,#offset,ResolvedDateTime)), 3)
) as inr
on inr.ResolvedDateTime = left(DATENAME(dw, dt), 3)
group by dt
order by dt
When using parameters that will be using one or many values you may tie them to a dataset as well.
Say if I have orders and people in a pretend sequence but I want to find orders of only certain people. I would follow a few steps:
I would create a dataset only for a parameter and call it 'People' for this example lets use a table variable that self executes and place this 'Query' box for a dataset.
declare #People Table ( personID int identity, person varchar(8));
insert into #People values ('Brett'),('Sean'),('Chad'),('Michael')
,('Ray'),('Erik'),('Queyn');
select * From #People
I would want to start with the dependency first which is a variable #Person I set up as an Integer and check 'Allow multiple values'. I then choose 'Available Values' on the left pane of the variable. I choose 'Get values from a query' choose my 'people' dataset from 1, choose PersonID as the Value field, and person as the label.
Now my parameter is bound and I can move on to my orders set. Again create a Dataset but call this one 'OrdersMain' and use a self extracting table variable but I am adding a predicate now referencing my variable from above as well.
declare #Orders table ( OrderID int identity, PersonID int, Desciption varchar(32), Amount int);
insert into #Orders values (1, 'Shirt', 20),(1, 'Shoes', 50),(2, 'Shirt', 22),
(2, 'Shoes', 52),(3, 'Shirt', 20),(3, 'Shoes', 50),(3, 'Hat', 20),
(4, 'Shirt', 20),(5, 'Shirt', 20),(5, 'Pants', 30), (6, 'Shirt', 20),
(6, 'RunningShoes', 70),(7, 'Shirt', 22),(7, 'Shoes', 40),(7, 'Coat', 80)
Select * from #Orders where PersonID in (#Person)
Now if populate my report with a tablix item and put the values from 'OrdersMain' in a tablix a user is prompted with a label for Brett, Sean, etc.. but the id is used for the orders to limit the scope of the dataset.
Optional
You can repeat step 1 for a SUBSET of people in another dataset and call it 'Defaults'. Then with an expanse of step 2 leave everything as is, but add this new dataset to 'Default Values' get from a query. This way I could create a temp table to get some of my people I most often use and then set them to be defaults instead. This would make the report auto execute when called.
Filtering can mean other things in SSRS as well. You can on any dataset see on the left pane a 'filter' and you may apply this. Keep in mind this will evaluate the whole expression first and then filter it. This use IMHO is best with shared datasets that are rather small and fast. Or you can use the filter clause in tablix elements as well which often is good when you want three objects from the same set but different predicates evaluated after runtime but to limit scope with reuse of one dataset for many objects.