I have three tables as following and I try to group by over three elements to display all possible combinations
Play
--------------------------------
id typeId periodId
--------------------------------
1 a 1
2 b 1
3 b 1
4 b 1
5 a 2
6 b 1
7 a 1
8 b 2
Period
-------------
periodId
-------------
1
2
3
Type
-------------
typeId
-------------
a
b
c
I tried this but it doesn't work, I see some NULL values but the group by doesn't work.
SELECT type, p, count(*) as superNiceCount
FROM Play
RIGHT JOIN Period pp ON Play.periodId = Period.periodId
RIGHT JOIN Type tt ON Play.typeId = Type.typeId
GROUP BY tt.typeId, pp.periodId
The expected result would be
-------------------------
type p superNiceCount
-------------------------
a 1 2
a 2 1
a 3 0
b 1 4
b 2 1
b 3 0
c 1 0
c 2 0
c 3 0
How may I achieve that ?
see if this works
SELECT ty.typeId as type, pe.periodId as p, count(pl.id) as superNiceCount
FROM Period pe
CROSS JOIN Type ty
LEFT JOIN Play pl ON (pl.periodId = pe.periodId AND pl.typeId = ty.typeId)
GROUP BY ty.typeId, pe.periodId
if not try
SELECT ty.typeId as type, pe.periodId as p, count(pl.id) as superNiceCount
FROM (
SELECT * FROM
Period pe
CROSS JOIN Type ty
) as t1
LEFT JOIN Play pl ON (pl.periodId = t1.periodId AND pl.typeId = t1.typeId)
GROUP BY ty.typeId, pe.periodId
Related
I have a database table products with the following columns.
ID | segment_key | segment_value
1 | Mo | 1
2 | Mo | 3
4 | Jo | 1
5 | Jo | 2
6 | Ta | 1
For any given key I need to find the next available segment_value for me to record in the same table.
ie. for the following segment_key list, the expected outputs are
Mo -> 2
Jo -> 3
Ta -> 2
Ji -> 1
I tried the solution mentioned here but I cannot seem to get the right output.
This is my failed attempt.
SELECT t1.segment_value
FROM products t1
WHERE NOT EXISTS (
SELECT *
FROM products t2
WHERE t2.segment_value = t1.segment_value + 1 and t2.segment_key='Mo' and t2.is_active=1
)
LIMIT 1
You can try to use CTE RECURSIVE to get the gap of all values. then do CROSS JOIN fill in the gap of value from each segment_key.
Final using OUTER JOIN and filter segment_key IS NULL which represent the gap of values
Query #1
WITH RECURSIVE CTE AS(
SELECT MIN(segment_value) val,MAX(segment_value) + 1 max_val
FROM products
UNION ALL
SELECT val + 1 ,max_val
FROM CTE c
WHERE val + 1 <= max_val
)
SELECT c.segment_key,MIN(val) segment_value
FROM (
SELECT DISTINCT val,segment_key
FROM CTE
CROSS JOIN products
) c
LEFT JOIN products p
ON c.val = p.segment_value AND c.segment_key = p.segment_key
WHERE p.segment_key IS NULL
GROUP BY c.segment_key;
segment_key
segment_value
Mo
2
Jo
3
Ta
2
View on DB Fiddle
In MYSQL DB, I have people_table :
------------------------------------------
people_table
------------------------------------------
person_ID(INT) name(VARCHAR(45))
1 A
2 B
3 C
4 D
------------------------------------------
and lend_borrow_money_table
------------------------------------------
lend_borrow_money_table
------------------------------------------
bill(DATE) lender_ID money(INT) borrower_ID
2018-11-1 1 100 2
2018-11-2 2 200 3
2018-11-3 3 300 4
2018-11-30 2 400 3
------------------------------------------
Now I Want select result like this
------------------------------------------
name lend borrow total
A 500 0 500
B 400 500 -100
C 0 600 -600
D 0 300 -300
------------------------------------------
In my way, I use join select to group by twice
but I think this is not best solution
SELECT Lender.name,Lend.lend,SUM(money) AS borrow
FROM lend_borrow_money_table
INNER JOIN people_table AS Borrower ON people_table.ID = lend_borrow_money_table.borrower_ID
INNER JOIN
(
SELECT SUM(money) as lend
FROM lend_borrow_money_table
WHERE bill<'2018/11/31' AND bill>'2018/11/1'
GROUP BY lender_ID
)AS Lend ON Lend.lender_ID
INNER JOIN people_table AS Lender ON people_table.ID = lend_borrow_money_table.lender_ID
WHERE bill<'2018/12/1' AND bill>'2018/11/1'
GROUP BY borrower_ID
My Question is that how to using GROUP BY twice but not with JOIN itself?
You can try below
select a.name,sum(b.money) as lend, sum(c.money) as borrow, sum(b.money)-sum(c.money) as total
from people_table a
left join lend_borrow_money_table b on a.id=b.lender_ID
left join lend_borrow_money_table c on a.id=c.borrower_ID
where bill>'20181101' and bill<'20181201'
group by a.name
I just want to merge the content of 2 tables and display it based on the ID.
Both the table has 3 entries.
Table a - Sampling order
Date Docname Products Quantity ID
1 A A 1 1
2 B B 2 1
3 C C 3 1
Table B - Representative locations
Date Area lat long ID
1 a 1 1 1
2 b 2 2 1
3 c 3 3 1
The output should generate like 3 rows with all the table A columns and B columns where ID = Specified ID
I need a output like this
Date Docname product Quantity Area lat long
1 A A 1 a 1 1
2 B B 2 b 2 2
3 C C 3 c 3 3
But its generating 9 rows (3*3) and duplicating the numbers of rows present in both the tables.
Its generating
Date Docname product Quantity Area lat long
1 A A 1 a 1 1
2 B B 2 b 2 2
3 C C 3 c 3 3
1 A A 1 a 1 1
2 B B 2 b 2 2
3 C C 3 c 3 3
1 A A 1 a 1 1
2 B B 2 b 2 2
3 C C 3 c 3 3
Combing number of rows in A * B - I just need only 3 rows with respect to ID.
Query -
$Report = DB::table('sampling_order')
->join('representativelocations','representativelocations.representativeid','=','sampling_order.representativeid')
->select('sampling_order.representativeid as representativeid',
'sampling_order.date as date',
'sampling_order.doctor_name as doctor_name',
'sampling_order.products as products',
'sampling_order.quantity as quantity',
'representativelocations.latitude as latitude',
'representativelocations.longitude as longitude',
'representativelocations.area as area')
->whereBetween('sampling_order.date', [$Datefrom, $Dateto])
->where('sampling_order.representativeid','=',$Representativeid)->get();
What I can see, all Id is '1' in two tables,
so it should be 3 * 3 = 9 rows in result.
I guess you may want this:
id product area-A area-B area-C
1____A____1____2_____3
1____B____2____3_____4
if so. you need to join three times.
SELECT * FROM A
LEFT JOIN (SELECT *, area AS area-A FROM B WHERE area = 'a' ) AS B ON B.id = A.id
LEFT JOIN (SELECT *, area AS area-B FROM B WHERE area = 'b' ) AS C ON C.id = A.id
LEFT JOIN (SELECT *, area AS area-C FROM B WHERE area = 'c' ) AS D ON D.id = A.id
Hope this is what you want.
Basing on the requirement, i think you should try joining on date not ID as below. This will return 3 rows as you are expecting.
select so.date,so.Docname,so.products,so.Quantity,rl.Area,rl.lat,rl.long from Sampling_order AS so
INNER JOIN Representative_locations as rl ON so.Date = rl.Date
WHERE so.ID = 1
Change table names and column names as needed.
I have 3 tables like:
owner_details:-
owner_id owner_name
---------------------
1 A
2 B
3 C
-------------------
vehicle_owner:-
v_id vehicle_id owner_id
-------------------------
1 1 1
2 2 2
3 4 1
4 3 1
5 5 3
transaction:-
id v_id amount transaction_type
--------------------------------
1 1 100 0
2 2 250 1
3 1 150 1
4 3 450 1
5 1 200 0
6 4 300 1
7 5 150 0
8 5 200 1
transaction_type= 0 then (-) transaction_type=1 then (+)
Owner A (1) have 3 vehicles with v_id (1,3,4) in table vehicle_owner.
v_id (1,3,4) have 5 entries in table transaction (1,3,4,5,6) with sum of amount 600 (-100+150+450-200+300)
Now I want listing like this:-.
owner_id owner_name amount
---------------------
1 A 600
2 B 250
3 C 50
-------------------
You can use the following query:
SELECT od.owner_id, od.owner_name, SUM(t.amount) AS amount
FROM owner_details od INNER JOIN vehicle_owner vo ON od.owner_id = vo.owner_id
INNER JOIN `transaction` t ON vo.v_id = t.v_id
GROUP BY od.owner_id
If you want to use the additional transaction_type you can use the following:
SELECT od.owner_id, od.owner_name, SUM(CASE WHEN t.transaction_type = 0 THEN t.amount * -1 ELSE t.amount END) AS amount
FROM owner_details od INNER JOIN vehicle_owner vo ON od.owner_id = vo.owner_id
INNER JOIN `transaction` t ON vo.v_id = t.v_id
GROUP BY od.owner_id
demo: http://sqlfiddle.com/#!9/c5f8d/1/1
Try this:
SELECT A.owner_id, A.owner_name, SUM(IFNULL(amount,0)) AMOUNT
FROM owner_details A LEFT JOIN
vehicle_owner B
ON A.owner_id=B.owner_id
LEFT JOIN `transaction` C
ON C.v_id=B.v_id
GROUP BY A.owner_id, A.owner_name;
It works for me
SELECT od.owner_id,
od.owner_name,
Sum(t.amount) AS amount
FROM owner_details od
INNER JOIN vehicle_owner vo
ON od.owner_id = vo.owner_id
INNER JOIN (SELECT v_id,
Coalesce(Sum(CASE
WHEN type = 0 THEN -amount
ELSE +amount
end), 0.0) AS amount
FROM `transaction`
GROUP BY v_id) t
ON vo.v_id = t.v_id
GROUP BY od.owner_id
Thanks Sebastian Brosch for quick response !!!
I have a table where exists 4 entries like this.
class_type
id type
1 A
2 B
3 M
4 T
and another table where these values are foreign key.
id number id_class_type
1 10 1
2 11 1
3 12 2
4 13 1
5 14 2
6 15 3
7 16 1
8 17 3
So what i want is count(*) and group by id_class_type but with all class_type (1,2,3,4) although there is not present the id 4.
if you want only the class tha match you can use inner join
select a.class_type, count(*)
from class_type a
inner join table2 b on a.id = b.id_class_type
group by a.class_type
otherwise you can use left join
select a.class_type, count(*)
from class_type a
left join table2 b on a.id = b.id_class_type
group by a.class_type