How to merge two tables using single query - mysql

I have three tables named receipt, receiptdet. The receipt table store record of the receipt information while the receiptdet stores the fees details in that receipt.
Table receipt:
receiptno | payor | amount
66 | 333 | 1600
67 | 332 | 1500
68 | 215 | 300
Table receiptdet:
receiptno | fee | amount
66 | 21 | 50
66 | 33 | 50
66 | 55 | 1500
67 | 55 | 1500
68 | 12 | 100
68 | 44 | 100
68 | 22 | 100
Table fees:
Id | code | inassess
12 | Xbre | 0
21 | Drop | 0
22 | Stest | 0
33 | Perm | 0
44 | Afee | 0
55 | TFee | 1
I want a query that will display records based on the selected field if "INASSESS" field is either 0 or 1 AND SUM THE TOTAL AMOUNT ON RECEIPDET table.
DESIRED OUTPUT
receiptno | payor | SUM(receiptdet.amount) | inassess
66 | 333 | 1500 | 1
67 | 332 | 1500 | 1
OR
receiptno | payor | SUM(receiptdet.amount) | inassess
66 | 333 | 100 | 0
68 | 215 | 300 | 0
so far i have to working separate query for both table. and i want to make it as one single query if someone can help me i will greatly appreciate it. thanks in advance
SELECT
receipt.receiptno,
receipt.amount
FROM
receipt ORDER
BY LENGTH(receipt.receiptno), receipt.receiptno
SELECT
Sum(receiptdet.amount),
receiptdet.student,
feetype.inassess,
receiptdet.receiptno
FROM
receiptdet
Left Join fees ON receiptdet.fee = fees.id
Left Join feetype ON fees.feetype = feetype.id
WHERE
feetype.inassess = '0' AND
receiptdet.receiptno = '66'

You can use JOINs to put all the tables together by their linking columns, then use GROUP BY to group the data according to receiptno and inassess. One query will give you all the data you require:
SELECT r.receiptno, r.payor, SUM(rd.amount) AS fees, f.inassess
FROM receipt r
LEFT JOIN receiptdet rd ON rd.receiptno = r.receiptno
JOIN fees f ON f.id = rd.fee
GROUP BY f.inassess, r.receiptno
For your sample data, this gives:
receiptno payor fees inassess
66 333 100 0
68 215 300 0
66 333 1500 1
67 332 1500 1
SQLFiddle

Related

select all rows with distinct and condition in MySQL

Hi guys I new in mySQL and I have problem with query. I was trying to write some Query which get me all records from table and if I have two records with the same date i need get only record between this two which have manual_selection = 1.
So result should be all records from my table except id = 1401 and id = 1549
my table
I tried to combine how can I get this records like this:
SELECT * FROM project.score WHERE project_id = 358
AND crawled_at IN(SELECT crawled_at FROM project.score WHERE project_id = 358
AND manual_selection = 1 GROUP BY crawled_at)
ORDER BY crawled_at;
SELECT * FROM project.score WHERE project_id = 358
GROUP BY crawled_at HAVING manual_selection = 1;
but all my way always get only rows with manual_selection = 1. I havent idea how can I distinct rows with duplicate "crawled_at" on case where manual_selection = 1. Can someone help me?
Try this:
select main.id, main.project_id, main.crawled_at, main.score, main.manual_selection
from dcdashboard.moz_optimization_keywords as main
left join dcdashboard.moz_optimization_keywords as non_manual_selection on non_manual_selection.crawled_at = main.crawled_at and non_manual_selection.manual_selection != 1
group by main.crawled_at;
Result with data set from question:
+------+------------+---------------------+-------+------------------+
| id | project_id | crawled_at | score | manual_selection |
+------+------------+---------------------+-------+------------------+
| 807 | 360 | 2016-02-06 00:00:00 | 76 | 0 |
| 1001 | 360 | 2016-02-20 00:00:00 | 76 | 0 |
| 223 | 360 | 2016-11-28 00:00:00 | 76 | 0 |
| 224 | 360 | 2016-12-05 00:00:00 | 76 | 0 |
| 670 | 360 | 2016-12-19 00:00:00 | 76 | 0 |
| 1164 | 360 | 2017-04-19 00:00:00 | 78 | 1 |
| 1400 | 360 | 2017-09-13 00:00:00 | 96 | 1 |
| 1548 | 360 | 2017-09-15 00:00:00 | 96 | 1 |
+------+------------+---------------------+-------+------------------+
8 rows in set (0.00 sec)

delete min. values from records after comparing two values from table in sql

I need help to filter data from table: tbl_entso_cdbf.
The table has trade information from one area to other area:
Utc | date |area_in|area_out| value |
------------------------------------------------------------------
2015-12-05T03:00Z |2015-12-05 03:00:00| 275 | 40 | 320 |
2015-12-05T03:00Z |2015-12-05 03:00:00| 40 | 275 | 0 |
2015-12-06T03:00Z |2015-12-06 03:00:00| 100 | 175 | 550 |
2015-12-06T03:00Z |2015-12-06 03:00:00| 175 | 100 | 0 |
2015-11-04T03:00Z |2015-11-04 03:00:00| 280 | 310 | 0 |
2015-11-04T03:00Z |2015-11-04 03:00:00| 310 | 280 | 0 |
2016-09-19T00:00Z |2016-09-19 00:00:00| 187 | 292 | 45 |
2016-09-19T00:00Z |2016-09-19 00:00:00| 292 | 187 | 0 |
Table contains export and import values between area_in and area_out.
This table contains double entries in value column refere to date column.For ex., first two rows have same date and time 2015-12-05 03:00:00 but two different values 320 and 0. I want to have only one value 320 and delete second row which has 0 value. It means trade between area_in 275 and area_out 40 at same date and time 2015-12-05 03:00:00 should have unique positive value. Same implies for row no. 3, 4, 7 and 8.
But in rows 5 and 6 both have 0 values so I want to have only one record (any one of them).
So, in the end I want my table to be looked like:
Utc | date |area_in|area_out| value |
------------------------------------------------------------------
2015-12-05T03:00Z |2015-12-05 03:00:00| 275 | 40 | 320 |
2015-12-06T03:00Z |2015-12-06 03:00:00| 100 | 175 | 550 |
2015-11-04T03:00Z |2015-11-04 03:00:00| 310 | 280 | 0 |
2016-09-19T00:00Z |2016-09-19 00:00:00| 187 | 292 | 45 |
This table has millions of such kind of rows to filter. can any one help me to write a sql query ?
Find the rows you want to delete with this query:
select t0.*
from tbl_entso_cdbf t0
join tbl_entso_cdbf t1
on t1.Utc = t0.Utc
and t1.date = t0.date
and t1.area_in = t0.area_out
and t1.area_out = t0.area_in
where t0.value = 0
and (t1.value <> 0 or t1.area_in < t0.area_in);
The conditions are:
value = 0
There is another row with same Utc and same date but area_in and area_out are switched.
The value of the other row is not 0 or area_in is smaller.
The query will return the follwing rows:
| Utc | date | area_in | area_out | value |
|-------------------|---------------------|---------|----------|-------|
| 2015-12-05T03:00Z | 2015-12-05 03:00:00 | 40 | 275 | 0 |
| 2015-12-06T03:00Z | 2015-12-06 03:00:00 | 175 | 100 | 0 |
| 2015-11-04T03:00Z | 2015-11-04 03:00:00 | 310 | 280 | 0 |
| 2016-09-19T00:00Z | 2016-09-19 00:00:00 | 292 | 187 | 0 |
Now use it in a subquery of the delete statement:
delete t1
from tbl_entso_cdbf t1
natural join (
select t0.*
from tbl_entso_cdbf t0
join tbl_entso_cdbf t1
on t1.Utc = t0.Utc
and t1.date = t0.date
and t1.area_in = t0.area_out
and t1.area_out = t0.area_in
where t0.value = 0
and (t1.value <> 0 or t1.area_in < t0.area_in)
) t0;
NATURAL JOIN means that all column values must be equal. If you had a primary (or any unique) key, you would only need to select the primary (unique) key columns in the subquery instead of *.
Now only the following rows are left in the table:
| Utc | date | area_in | area_out | value |
|-------------------|---------------------|---------|----------|-------|
| 2015-12-05T03:00Z | 2015-12-05 03:00:00 | 275 | 40 | 320 |
| 2015-12-06T03:00Z | 2015-12-06 03:00:00 | 100 | 175 | 550 |
| 2015-11-04T03:00Z | 2015-11-04 03:00:00 | 280 | 310 | 0 |
| 2016-09-19T00:00Z | 2016-09-19 00:00:00 | 187 | 292 | 45 |
I assume that your table with primary key looks something like this:
pk | Utc | date |area_in|area_out| value |
-----------------------------------------------------------------------
1 | 2015-12-05T03:00Z |2015-12-05 03:00:00| 275 | 40 | 320 |
2 | 2015-12-05T03:00Z |2015-12-05 03:00:00| 40 | 275 | 0 |
3 | 2015-12-06T03:00Z |2015-12-06 03:00:00| 100 | 175 | 550 |
4 | 2015-12-06T03:00Z |2015-12-06 03:00:00| 175 | 100 | 0 |
5 | 2015-11-04T03:00Z |2015-11-04 03:00:00| 280 | 310 | 0 |
6 | 2015-11-04T03:00Z |2015-11-04 03:00:00| 310 | 280 | 0 |
7 | 2016-09-19T00:00Z |2016-09-19 00:00:00| 187 | 292 | 45 |
8 | 2016-09-19T00:00Z |2016-09-19 00:00:00| 292 | 187 | 0 |
With execution this query you should be able to delete the rows you want to get rid of:
DELETE FROM tbl_entso_cdbf
WHERE pk IN (SELECT PK_DEL
FROM (Select pk AS PK_DEL
, utc
, value
, ROW_NUMBER() OVER(PARTITION BY utc ORDER BY value desc) AS DUB_IND
FROM tbl_entso_cdbf
WHERE DUB_IND <> 1
)
);
That query is suposed to delete all rows where the pk in in the return of the subquery. The subquery shall return all primary keys of the records, where the value is minor as the duplicates. But please, before trying this make shure, that this query returns the wanted result of records that should be deleted:
Select pk AS PK_DEL
, utc
, value
, ROW_NUMBER() OVER(PARTITION BY utc ORDER BY value desc) AS DUB_IND
FROM tbl_entso_cdbf
WHERE DUB_IND <> 1
If so, you should be able to delete the duplicates!

Pivot table query in mysql

Is there a way to do a query in mysql with this scenario.
i have a table
group_name | cost_period | books_cost | others_cost
group_A | 1/01/2015 | 100 | 200
group_A | 1/02/2015 | 56 | 86
group_A | 1/01/2015 | 22 | 222
group_A | 1/03/2015 | 30 | 40
group_B | 1/02/2015 | 50 | 10
group_B | 1/02/2015 | 45 | 10
group_B | 1/01/2015 | 22 | 15
group_C | 1/02/2015 | 45 | 20
and i want it to have this format after the query
JAN-2015 FEB-2015 MAR_2015 total
group_A
sum of book cost 122 56 30 208
sum of others cost 422 86 40 548
group_B
sum of book cost 22 95 0 117
sum of others cost 15 20 0 45
group_C
sum of book cost 0 45 0 45
sum of others cost 0 20 0 20
is there a way this is possible by a query to avoid using a pivot tool once data is gathered? since jasper's crosstabs are not that flexible
thanks

Query to get data from four tables

i have following scheme,
purchase_order
+-------------------+----------------------+
| purchase_order_id | purchase_order |
+-------------------+----------------------+
| 54 | Purchase Order 12345 |
| 56 | po-laptop-hp-3 |
| 57 | po-laptop-hp-1 |
+-------------------+----------------------+
purchase_order_detail
+--------------------------+-------------------+---------+------------------+
| purchase_order_detail_id | purchase_order_id | item_id | ordered_quantity |
+--------------------------+-------------------+---------+------------------+
| 61 | 54 | 279 | 500 |
| 62 | 54 | 286 | 700 |
| 63 | 56 | 279 | 43 |
| 64 | 57 | 279 | 43 |
| 65 | 57 | 286 | 43 |
| 66 | 57 | 287 | 43 |
+--------------------------+-------------------+---------+------------------+
delivery_order
+-------------------+--------------------------+-------------------+
| delivery_order_id | purchase_order_detail_id | recieved_quantity |
+-------------------+--------------------------+-------------------+
| 62 | 61 | 250 |
| 63 | 62 | 300 |
| 64 | 63 | 34 |
| 65 | 64 | 34 |
| 66 | 65 | 34 |
| 67 | 66 | 34 |
| 68 | 61 | 34 |
| 69 | 61 | 34 |
+-------------------+--------------------------+-------------------+
stock
+----------+-------------------+------------+----------+------------------+---------------+
| stock_id | delivery_order_id | project_id | quantity | initial_quantity | stock_type_id |
+----------+-------------------+------------+----------+------------------+---------------+
| 12 | 62 | 1 | 60 | 60 | 1 |
| 13 | 63 | 1 | 120 | 120 | 1 |
| 14 | 63 | 1 | 50 | 50 | 1 |
| 15 | 64 | 1 | 12 | 12 | 1 |
| 16 | 62 | 1 | 120 | 120 | 1 |
| 17 | 62 | 1 | 12 | 12 | 1 |
+----------+-------------------+------------+----------+------------------+---------------+
i have write this query but it returns duplicate results
SELECT po.created_on
, po.purchase_order
, i.item_name
, u.unit_name
, pod.ordered_quantity
, do.recieved_quantity
, do.recieved_on
, po.remarks
FROM purchase_order po
, purchase_order_detail pod
, delivery_order do
, stock s
, item i
, unit u
WHERE u.unit_id = i.unit_id
AND i.item_id = pod.item_id
AND po.purchase_order_id = pod.purchase_order_id
AND pod.purchase_order_detail_id = do.purchase_order_detail_id
AND do.delivery_order_id = s.delivery_order_id
AND s.project_id = 1
ORDER BY po.purchase_order_id
, pod.item_id
;
The results
+---------------------+----------------------+------------+-----------+------------------+-------------------+---------------------+---------------------------------------+
| created_on | purchase_order | item_name | unit_name | ordered_quantity | recieved_quantity | recieved_on | remarks |
+---------------------+----------------------+------------+-----------+------------------+-------------------+---------------------+---------------------------------------+
| 2015-02-24 22:48:15 | Purchase Order 12345 | HP Laptops | Unit | 500 | 250 | 2015-02-21 00:00:00 | Adding first Purchase Order as a Test |
| 2015-02-24 22:48:15 | Purchase Order 12345 | HP Laptops | Unit | 500 | 250 | 2015-02-21 00:00:00 | Adding first Purchase Order as a Test |
| 2015-02-24 22:48:15 | Purchase Order 12345 | Lenovo | Unit | 700 | 300 | 2015-02-21 00:00:00 | Adding first Purchase Order as a Test |
| 2015-02-24 22:48:15 | Purchase Order 12345 | Lenovo | Unit | 700 | 300 | 2015-02-21 00:00:00 | Adding first Purchase Order as a Test |
| 2015-02-24 22:55:40 | po-laptop-hp-3 | HP Laptops | Unit | 43 | 34 | 2015-02-21 00:00:00 | dfgsdfgsd |
+---------------------+----------------------+------------+-----------+------------------+-------------------+---------------------+---------------------------------------+
relationship is one to many from top to bottom.
What I wanted to get is the each purchase_order , his ordered quantity of each item, and total recieved quantity, and quantity in stock where project_id = 1 from stock.
i am expecting something like this,
+-------------------+---------+------------------+---------------+----------+
| purchase_order_id | item_id | ordered_quantity | totalReceived | quantity |
+-------------------+---------+------------------+---------------+----------+
| 54 | 279 | 500 | 314 | 192 |
| 54 | 286 | 700 | 300 | 170 |
| 56 | 279 | 43 | 34 | 12 |
+-------------------+---------+------------------+---------------+----------+
EDIT
Thank you for clearing up the mistake in my first part. I realize now that we cannot do all calculations in a single query (because we group on different columns in various parts) so I started by writing individual subqueries and joining them together. The steps went something like this:
Get the sum of received total received quantity for each
purchase_order_detail_id from the delivery_order table.
Join that subquery with the delivery_order table itself to get the totalReceived for the various delivery_order_id values.
Join that result set with the purchase_order_detail table to get the purchase_order_id, item_id, and ordered_quantity for each delivery_order_id.
We now have a result set including the delivery_order_id, purchase_order_id, item_id, ordered_quantity, and total received. The last two things are:
Get the SUM() of quantity for each delivery_order_id from the stock table.
Join that with our above result set on the condition that order_id matches (so we will only get one row) and that project_id is 1 (so we only get the necessary delivery_order_id values). I put that condition in the WHERE clause of the sum subquery.
Here is your final query:
SELECT tmp1.purchase_order_id, tmp1.item_id, tmp1.ordered_quantity, tmp1.totalReceived, tmp2.quantity
FROM(
SELECT tmp.delivery_order_id, pod.purchase_order_id, pod.item_id, pod.ordered_quantity, tmp.totalReceived
FROM purchase_order_detail pod
JOIN(
SELECT do.delivery_order_id, tmp.purchase_order_detail_id, tmp.totalReceived
FROM delivery_order do
JOIN(
SELECT do.purchase_order_detail_id, SUM(do.received_quantity) AS totalReceived
FROM delivery_order do
GROUP BY do.purchase_order_detail_id) tmp ON tmp.purchase_order_detail_id = do.purchase_order_detail_id)
tmp ON tmp.purchase_order_detail_id = pod.purchase_order_detail_id) tmp1
JOIN(
SELECT s.delivery_order_id, SUM(quantity) AS quantity
FROM stock s
WHERE s.project_id = 1
GROUP BY s.delivery_order_id) tmp2 ON tmp2.delivery_order_id = tmp1.delivery_order_id;
Here is the SQL Fiddle. It shows all of the intermediate steps too, if you'd like to see how the results came together individually.
Try modifying your query to use DISTINCT and OUTER JOINs instead of cartesian ("comma") joins.
SELECT DISTINCT po.created_on
, po.purchase_order
, i.item_name
, u.unit_name
, pod.ordered_quantity
, do.recieved_quantity
, do.recieved_on
, po.remarks
FROM purchase_order po
LEFT JOIN purchase_order_detail pod USING (purchase_order_id)
LEFT JOIN delivery_order do USING (purchase_order_detail_id)
LEFT JOIN stock s USING (delivery_order_id)
LEFT JOIN item i USING (item_id)
LEFT JOIN unit u USING (unit_id)
ORDER BY po.purchase_order_id
, pod.item_id
;

Dynamic Cross Tab in MySQL

I have the following table with the following data
Year | Age Group | Male | Female
2000 | 0 - 25 | 50 | 100
2000 | 26 above | 40 | 75
2001 | 0 - 25 | 150 | 86
2001 | 26 above | 65 | 83
I would like to create a cross tab in the following format
| Male | Female
2000 | 90 | 175
0 - 25 | 50 | 100
26 above | 40 | 75
2001 | 215 | 169
0 - 25 | 150 | 86
26 above | 65 | 83
I will be very grateful for your assistance.
SQLFiddle example:
select * from
(
select year,ageGroup,male,female from t
union all
select year,'' ageGroup,sum(male) male,sum(female) female
from t group by year
) st
order by year,agegroup