Adjacent row groups one next to another - reporting-services

In one order I can have many customers and many products.
I've got 3 tables with order details: Order_details, Order_customers and Order_products. Query to my view used as data set returns 8 rows when in one order i have 2 customers and 4 products. In Report Builder I group by Order_id but then I have got 8 row (2 customers x 4 products). If I ad group by Customer_ID and adjacent group by Product_ID then in column firs show customers id's and under product id's.
My view query looked like beneath:
select od.Order_id, oc.Customer_ID, oc.Customer_detail, op.Product, op.Product_detail
from Order_details od
left join Order_products op on od.Order_id = op.Order_id
left join Order_customers oc on od.Order_id = oc.Order_id
I want to group columns to get result looked like this:
+-----------+--------------+-----------------+-----------+----------------+
| Order ID | Customer ID | Customer detail | Product | Product detail |
+-----------+--------------+-----------------+-----------+----------------+
| | Customer_1 | Cusotmer_name | Product_1 | Product1_nuber |
| 1234 | | | Product_2 | Product2_nuber |
| | Cusotmer_2 | Cusotmer_name | Product_3 | Product3_nuber |
| | | | Product_4 | Product4_nuber |
+-----------+--------------+-----------------+-----------+----------------+

Can you try this - start with the detail and then add the groups.
Example:
First add the 'Product' and 'Product Detail' to the report.
Then, right click on Product row and select 'Add Parent Group' and choose 'Customer Detail' (you may or may not add header and footer for the group).
Then right click the 'Customer Detail' row and select 'Add Parent Group' and choose 'Customer ID' (you may or may not add header and footer for the group).
Then right click the 'Customer ID' row and select 'Add Parent Group' and choose 'Order ID' (you may or may not add header and footer for the group)
Hope this helps.

Related

Sql left outer join with three tables

I am developing basically an e-commerce application. Application has two pages (all product and my-basket) authenticated user can add product to own basket. and I have three tables, the tables contains following data. I want to if the user adds product to own basket, these products don't exist on this user's all product page.
How should be the SQL query? I am looking query for all product page. so query's return type must be Product.
If user added any products to own basket on all product page these products
shouldn't see on the all product page for this user.
PRODUCT TABLE
+-------+--------+
| id | name |
+-------+--------+
| 1 | p1 |
| 2 | p2 |
+-------+--------+
USER TABLE
+-------+--------+
| id | name |
+-------+--------+
| 3 | U1 |
| 4 | U2 |
+-------+--------+
BASKET TABLE
+-------+---------+-------------+
| id | fk_user | fk_product |
+-------+---------+-------------+
| 5 | 3 | 1 |
| 6 | 4 | 2 |
+-------+---------+-------------+
So if authenticated user's id is 3. The user should see p2 product on own all product page.
try this:
SELECT product.name
FROM product
LEFT JOIN basket ON basket.fk_product = product.id
WHERE (basket.fk_user != 3 OR basket.fk_user IS NULL)
Check my demo query
If you want you can also join the user table but with the data you gave me is not necessary.
A left join keeps all rows in the first (product) table plus all rows in the second (basket) table, when the on clause evaluates to true.
When the on clause evaluates to false or NULL, the left join still keeps all rows in the first table with NULL values for the second table.
or, more commonly...
SELECT p.name
FROM product p
LEFT JOIN basket b
on b.fk_product = p.id
AND b.fk_user = 3
WHERE b.fk_user is null
What you are describing sounds like NOT EXISTS:
SELECT p.name
FROM product p
WHERE NOT EXISTS (SELECT 1
FROM basket b
WHERE b.fk_product = f.id AND
b.fk_user = 3
);
This seems like the most direct interpretation of your question.

MySQL conditional select when a inner join involves

I am working on a project where we develop a tourist app. Some items are add to the system as
advertisements (Hotels, Night clubs) and some items add as useful information (beaches,national parks)
I have a table called items.
items
id | category_id | name | is_payment
1 | 1 | hotel califonia | 1
2 | 1 | hotel hilton | 1
3 | 2 | Yala national park | 0
4 | 2 | Kumana national park| 0
here category_id refers the categories table.
categories
id | name | type
1 | Hotels | commercial
2 | National parks | non-commercial
I want to select all the items from the item table.
But if it's a commercial item I need to check whether payment is made or not before display to the end users.
I don't have to show anything what I did up-to now.
I though the CASE function and IF function as well. But I don't know how to link those with this case study.
I have no idea how to do this.
I below query you can I am taking all non-commercial item Or if it is commercial then I am checking payment is also done using and operator.
SELECT i.*
FROM items i
JOIN categories c
ON i.category_id = c.id
WHERE c.type != 'commercial'
OR (c.type = 'commercial' AND i.is_payment = 1)
If you are looking for another query other than the above answer...
select a.* from items a join categories b on a.category_id=b.id and b.type='commercial' and a.is_payment=1
union all
select a.* from items a join categories b on a.category_id=b.id and b.type<>'commercial';

Make an alias column with custom string in MySQL

I have a MySQL tables like this:
##customer##
+-----------+----+---------+
|customer_id|name|telephone|
+-----------+----+---------+
| 1 |Andi|+62932011|
| 2 |Boby|+62928291|
| 3 |Jane|+62932212|
| 4 |John|+62999021|
| 5 |Beth|+62999021|
| 6 |Noel|+62999021|
+-----------+----+---------+
##plus_membership##
+-----------------+-----------+-------+------------+
|plus_membership_id|customer_id|status |requested_at|
+------------------+-----------+-------+------------+
| 1 | 1 | 1 | 2018-11-01 |
| 2 | 2 | 0 | 2018-11-03 |
| 3 | 4 | 2 | 2018-11-04 |
| 4 | 6 | 1 | 2018-11-05 |
+------------------+-----------+-------+------------+
there are two tables in above structure, the first is the customer with customer_id as the primary key and the second one is the plus_membership which has foreign key customer_id, the plus_membership table is a table to show a request if customer request to become a plus member, status 1 means the customer is apporved to be plus member. I need to select the customer table and add alias column lets say the alias column name is membership , that shows only regular or plus , plus means the customer in plus_membership status is 1, and regular if customer doesnt exist in plus_membership table or status is not 1 in membership table. for example:
SELECT *, .... AS membership FROM customer;
+-----------+----+---------+----------+
|customer_id|name|telephone|membership|
+-----------+----+---------+----------+
| 1 |Andi|+62932011| Plus |
| 2 |Boby|+62928291| Regular |
| 3 |Jane|+62932212| Regular |
| 4 |John|+62999021| Regular |
| 5 |Beth|+62999021| Regular |
| 6 |Noel|+62999021| Plus |
+-----------+----+---------+----------+
You can use Left Join between the two tables, and use Case .. When conditional expressions to evaluate membership accordingly.
Left Join would ensure that all the customer(s) from the customer table are considered, whether they have a corresponding matching row in the plus_membership table or not.
SELECT
c.customer_id,
c.name,
c.telephone,
(CASE WHEN pm.status = 1 THEN 'Plus' ELSE 'Regular' END) AS membership
FROM customer AS c
LEFT JOIN plus_membership AS pm
ON pm.customer_id = c.customer_id
Another approach can be using Correlated Subquery and Exists(). Generally, this would be less efficient than Left Join approach.
SELECT
c.customer_id,
c.name,
c.telephone,
CASE WHEN EXISTS (SELECT 1
FROM plus_membership AS pm
WHERE pm.customer_id = c.customer_id AND
pm.status = 1
)
THEN 'Plus'
ELSE 'Regular'
END AS membership
FROM customer AS c
We use EXISTS or IN to look up data in another table.
select customer_id, name, telephone,
case when customer_id in (select customer_id from plus_membership where status = 1)
then 'Plus' else 'Regular' end as membership
from customer
order by customer_id;

Calculating values in a hierarchy of a known depth

I have to query a few derived values from 2 tables. Their simplified structure is as follows:
Users
Users have a ID and a parent column which denotes the ID of their parent. Each user also has a commission value which denotes what % of sales that they get from the employees in their line.
Only employees can make sales and that information is recorded in the next table
+------------------------------------+
| ID Name Parent Commission |
+------------------------------------+
| 1 SeniorManager NULL 5 |
| 2 Manager 1 10 |
| 3 Employee1 2 13 |
| 4 Employee2 2 12 |
+------------------------------------+
Sales
This table records the sales from the employees linked through their ID. It records the sale amount as well as when the sale was made.
+---------------------------+
| user_id amount created_at |
+---------------------------+
| 3 100 2014-01-16 |
| 3 120 2014-01-16 |
| 3 110 2014-01-16 |
+---------------------------+
From the other parts of the system, I know the depth of a user given his ID. In the actual system, there is 7 fixed levels but I am simplifying it here for the sake of the question.
The query that I am trying to write is that: Given the ID of a SeniorManager and a date range, show a list of managers under him, the aggregated commissions of those managers as well as the commission expected from that manager. So given the data above one would expect:
+--------------------------------------------+
| Name Sales ManagerCommission Commission |
+--------------------------------------------+
| Manager 330 33.30 16.65 |
+--------------------------------------------+
The query I have so far is:
SELECT
users.name AS Name,
SUM(sales.amount) AS Sales,
SUM(sales.amount) * (users.commission/100) AS ManagerCommission
FROM
users
LEFT JOIN users AS employees
ON employees.parent = users.id
LEFT JOIN sales
ON sales.id = employees.id AND
sales.created_at BETWEEN DATE(?) AND DATE(?)
WHERE
users.parent = ?
GROUP BY
users.name
I am unsure how to get that last column value of the commission grouped by managers instead of employees. Also as a side question, is there a way to reuse the SUM(sales.amount) which is used twice in the select statement. I would rather not calculate the exact same value twice. I am planning on writing 7 queries, for each of the known depths. Is there a more efficient way of doing this?
Adding one join for each level of management:-
SELECT
senior_manager.name AS Name,
SUM(sales.amount) AS Sales,
SUM(sales.amount * manager.commission/100) AS ManagerCommission,
SUM(sales.amount) * (senior_manager.commission/100) AS SeniorManagerCommission
FROM
users AS senior_manager
LEFT JOIN users AS manager
ON manager.parent = senior_manager.id
LEFT JOIN users AS employees
ON employees.parent = manager.id
LEFT JOIN sales
ON sales.id = employees.id AND
sales.created_at BETWEEN DATE(?) AND DATE(?)
WHERE
senior_manager.id = ?
GROUP BY
senior_manager.name
SQL fiddle for it:-
http://www.sqlfiddle.com/#!2/2cfffe/4

Showing rows as columns in MySQL

I have a networks table and a groups table and they are linked by each group being connected to a network.
Each group have a type and some of these groups are special type of groups.
I'm trying to run query that will display each group that is a a special type to be displayed as a column showing how many people are in that group type.
Is that something that is possible? Having each group type being displayed as a column header.
Data:
Networks
id | name
1 | networka
2 | networkb
groups
id | name | type | network
1 | groupa | 1 | 1
2 | groupb | 2 | 2
3 | groupc | 3 | 1
type
id | name | special
1 | speciala | 0
2 | specialb | 1
I currently running:
SELECT Name FROM (
SELECT groups.Name FROM groups INNER JOIN group_types on groups.Type = group_types.Id WHERE group_types.SpecialType = 1 Group by groups.Type
) as s
which returns the list of groups with special type. But if I want to get more information such as the number of members in that group assuming I have a group_members table that links back to the groups table or the numbers of groups with that type.
I currently get two a row:
name
specialb
but I actually want to return back
specialb
(sub query to get more values for that special group)
If I'm understanding what you want correctly, write this:
select g.name, t.name, count(*)
from groups as g left join group_members as gm on gm.group=g.id left join types as t on t.id=g.type
group by g.name, t.name
then copy and paste into Excel using paste special > transpose.