what is wrong in this sql query [closed] - mysql

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I had created two Tables 'tbl_book_info' and 'tbl_books' (table descriptions
are below) in MySQL Database
what should I change in my SQL query
I had used subquery inside WHERE clause.
All Records of 'tbl_books'-
+-------+-------+--------+
| accid | accno | status |
+-------+-------+--------+
| 10001 | 101 | I |
| 10001 | 102 | I |
| 10001 | 103 | A |
| 10002 | 101 | A |
| 10002 | 102 | A |
| 10002 | 103 | I |
| 10002 | 104 | I |
| 10002 | 105 | I |
| 10003 | 101 | A |
| 10003 | 102 | A |
| 10003 | 103 | A |
| 10003 | 104 | I |
| 10003 | 105 | I |
| 10004 | 101 | A |
| 10004 | 102 | I |
| 10004 | 103 | A |
| 10004 | 104 | A |
| 10004 | 105 | A |
| 10005 | 101 | A |
| 10005 | 102 | A |
| 10005 | 103 | A |
| 10005 | 104 | A |
| 10005 | 105 | A |
+-------+-------+--------+
23 rows in set (0.00 sec)
All Records of 'tbl_book_info'-
+----------+------------------+-------+-------------+---------+---------+-------------+---------+--------+---------+---------+
| b_acc_id | b_name | b_qty | b_type | b_auth1 | b_auth2 | b_pub | b_pages | b_rack | b_price | b_about |
+----------+------------------+-------+-------------+---------+---------+-------------+---------+--------+---------+---------+
| 10001 | Java | 3 | Programming | lala | - | kallo | 800 | 1 | 799.00 | - |
| 10002 | Cpp | 5 | Programming | Kallo | - | Mehta group | 400 | 2 | 300.00 | - |
| 10003 | VB.net | 5 | Programming | lalaji | - | amam co. | 479 | 3 | 100.00 | - |
| 10004 | DBMS | 5 | prog | lalal | - | kallo | 888 | 3 | 499.00 | - |
| 10005 | computer network | 5 | Networking | Mirabai | - | kabirdas | 789 | 2 | 800.00 | - |
+----------+------------------+-------+-------------+---------+---------+-------------+---------+--------+---------+---------+
desc tbl_books;
+--------+------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra |
+--------+------------+------+-----+---------+-------+ | accid | int(5) | NO | PRI | 0 | | | accno | int(3) | NO | PRI | 0 | | | status | varchar(1) | YES | | A | |
+--------+------------+------+-----+---------+-------+
desc tbl_book_info;
+----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+----------------+
| b_acc_id | int(5) | NO | PRI | NULL | auto_increment |
| b_name | varchar(50) | NO | | NULL | |
| b_qty | int(2) | NO | | NULL | |
| b_type | varchar(30) | NO | | NULL | |
| b_auth1 | varchar(50) | NO | | NULL | |
| b_auth2 | varchar(50) | YES | | NULL | |
| b_pub | varchar(50) | NO | | NULL | |
| b_pages | int(4) | NO | | NULL | |
| b_rack | int(5) | NO | | NULL | |
| b_price | decimal(6,2) | NO | | NULL | |
| b_about | text | YES | | NULL | |
+----------+--------------+------+-----+---------+----------------+
Here tbl_books.accid REFERS tbl_book_info.b_acc_id
My query is:
select b_name, b_qty, b_acc_id , (count(*)) Issued, (count(*)) Available
From tbl_book_info
where tbl_book_info.b_acc_id in (select accid from tbl_books
where status = 'I'
GROUP BY status) ;
I want to perform join between the tables 'tbl_book_info' and 'tbl_books' to print the Result as
Desired Output:
+--------+-------+----------+--------+-----------+
| b_name | b_qty | b_acc_id | Issued | Available |
+--------+-------+----------+--------+-----------+
| Java | 3 | 10001 | 2 | 1 |
+--------+-------+----------+--------+-----------+
| Cpp | 5 | 10002 | 3 | 2 |
+--------+-------+----------+--------+-----------+
...(and more)
Output Came:
+--------+-------+----------+--------+-----------+
| b_name | b_qty | b_acc_id | Issued | Available |
+--------+-------+----------+--------+-----------+
| Java | 3 | 10001 | 4 | 4 |
+--------+-------+----------+--------+-----------+

If you want to do a Join, then you should do it, not doing a strange subquery in a where. You can do a Join and a conditional case to sum in two different columns the Issued and the Avalilables
Select a.b_name, a.b_qty, a.b_acc_id , sum(case
when b.status='I' then 1
else 0
end) as Issued,
sum(case
when b.status='A' then 1
else 0
end) as Available
From tbl_book_info a left join tbl_books b on a.b_acc_id=b.accid
group by a.b_name, a.b_qty, a.b_acc_id

In MySQL, you can take a short-cut for this type of query:
select bi.b_name, bi.b_qty, bi.b_acc_id,
sum( b.status = 'I' ) as Issued,
sum( b.status = 'A' ) as Available
from tbl_book_info bi left join
tbl_books b
on bi.b_acc_id = b.accid
group by bi.b_name, bi.b_qty, bi.b_acc_id;
MySQL treats boolean expressions as integers in a numeric context (such as SUM()). Also note that the table aliases are abbreviations for the table name.
With an index on books(acc_id, status), this might be faster using a subqueries:
select bi.b_name, bi.b_qty, bi.b_acc_id,
(select count(*)
from tbl_books b
where b.accid = bi.b_acc_id and
b.status = 'I'
) as Issued,
(select count(*)
from tbl_books b
where b.accid = bi.b_acc_id and
b.status = 'A'
) as Available
from tbl_book_info bi ;
The performance gain is by avoiding the work for the outer group by (typically a sort). The index can be used instead.

I have not tried this solution yet, but I can say that you need to do Group By accid column of tbl_books table. So please make following change in your query:
select b_name, b_qty, b_acc_id , (count(*)) Issued, (count(*)) Available
From tbl_book_info
where tbl_book_info.b_acc_id in (select accid from tbl_books
where status = 'I'
GROUP BY accid) ;

Related

Mysql - Calculate Times per month - organise result

I'm extracting data from sql by the following SQL Query
SELECT DISTINCT
SEC_TO_TIME(SUM(TIME_TO_SEC(transics_bco.arab))) AS arab,
transics_bco.plate
FROM transics_bco
WHERE transics_bco.extdate BETWEEN '2019-12-01' AND '2019-12-31'
GROUP BY transics_bco.plate
This gives me the following result:
-----------------------
| ARAB | Plate |
-----------------------
| 178:44:43 | 1ABC123 |
| 156:23:44 | 1DEF456 |
-----------------------
Is it possible to get the result shown as this;
---------------------------------------------------------------
| Plate | December 19 | January 20 | February 20 | March 20 |
---------------------------------------------------------------
| 1ABC123 | 178:44:43 | 120:34:56 | ... | ... |
| 1DEF456 | 156:23:44 | 102:34:54 | ... | ... |
| 1GHI789 | 111:22:33 | 156:35:35 | ... | ... |
---------------------------------------------------------------
SQL Sample: transics_bco
----------------------------------------
| id | plate | arab | extdate |
----------------------------------------
| 1 | 1ABC123 | 00:14:23 | 2019-12-01 |
| 2 | 1ABC123 | 00:10:20 | 2019-12-03 |
| 3 | 1ABC123 | 00:45:06 | 2019-12-07 |
| 4 | 1ABC123 | 00:54:45 | 2020-01-02 |
| 5 | 1ABC123 | 00:26:10 | 2020-01-03 |
| 6 | 1ABC123 | 00:43:28 | 2020-01-04 |
----------------------------------------
Would greatly appreciate pointers in the good direction
Adding db describe as requested in the comments;
-
Adding describe of Transics_bco as requested in the comments
===================================================================================================================================================================================================================================================================================================================
| Field | Type | Null | Key | Default | Extra |
===================================================================================================================================================================================================================================================================================================================
| id | int(11) | NO | PRI | null | auto_increment |
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| plate | varchar(255) | NO | | null | |
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| arab | time | NO | | 00:00:00 | |
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| extdate | date | NO | | null | |
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SELECT
plate,
december19,
january20,
february20,
march20
FROM
(
SELECT DISTINCT
a.plate,
(
CASE
WHEN
Month(a.extdate) = 12
AND Year(a.extdate) = 2019
THEN
Sec_to_time(Sum(Time_to_sec(a.arab)))
END
)
AS 'December19',
(
CASE
WHEN
Month(a.extdate) = 1
AND Year(a.extdate) = 2020
THEN
a.arab
END
)
AS 'January20, (CASE WHEN MONTH(a.extDate)=2 AND YEAR(a.extDate)=2020 THEN SEC_TO_TIME(SUM(TIME_TO_SEC(a.arab))) END) AS 'february20', (CASE WHEN MONTH(a.extDate)=3 AND YEAR(a.extDate)=2020 THEN SEC_TO_TIME(SUM(TIME_TO_SEC(a.arab))) END) AS 'march20', FROM transics_bco a WHERE transics_bco.extdate BETWEEN '2019-12-01' AND '2019-12-31'
GROUP BY
transics_bco.plate
)
T
GROUP BY
T.plate;

MYSQL Max Value of status

I have the following tables that records the details of letters vs actions, taken for them.
letter table
+-----------+-------------+
| letter_id | description |
+-----------+-------------+
| 1 | A |
| 2 | B |
| 3 | C |
| 4 | D |
+-----------+-------------+
action table
+-----------+--------+------------+---------------+
| action_id | ref_no | date | action_status |
+-----------+--------+------------+---------------+
| 1 | 1 | 2018-09-20 | On-Going |
| 2 | 1 | 2018-09-22 | Finished |
| 3 | 3 | 2018-09-16 | On-Going |
| 4 | 4 | 2018-09-26 | On-Going |
| 5 | 4 | 2018-09-27 | Finished |
+-----------+--------+------------+---------------+
And need to get the following output
+-----------+-------------+------------+---------------+
| letter_id | description | date | action_status |
+-----------+-------------+------------+---------------+
| 1 | A | 2018-09-22 | Finished |
| 2 | B | - | Pending |
| 3 | C | 2018-09-16 | On-Going |
| 4 | D | 2018-09-27 | Finished |
+-----------+-------------+------------+---------------+
I used the following query
select letter.letter_id,letter.description, action.date, action.action_status
from letter
left join action on letter.letter_id=action.ref_no
where (date in
(
select max(date) from action
where letter.letter_id=action.ref_no
))
But the above query generate the following output
+-----------+-------------+------------+---------------+
| letter_id | description | date | action_status |
+-----------+-------------+------------+---------------+
| 1 | A | 2018-09-20 | On-Going |
| 1 | A | 2018-09-22 | Finished |
| 2 | B | - | Pending |
| 3 | C | 2018-09-16 | On-Going |
| 4 | D | 2018-09-26 | On-Going |
| 4 | D | 2018-09-27 | Finished |
+-----------+-------------+------------+---------------+
I can not understand what I am going wrong. Can anyone help me ?
DROP TABLE IF EXISTS action;
CREATE TABLE action
(action_id SERIAL PRIMARY KEY
,letter_id INT NOT NULL
,date DATE NOT NULL
,action_status VARCHAR(20) NOT NULL
);
INSERT INTO action VALUES
(1,101,'2018-09-20','On-Going'),
(2,101,'2018-09-22','Finished'),
(3,103,'2018-09-16','On-Going'),
(4,104,'2018-09-26','On-Going'),
(5,104,'2018-09-27','Finished');
SELECT x.*
FROM action x
JOIN
( SELECT letter_id, MAX(date) max_date FROM action GROUP BY letter_id ) y
ON y.letter_id = x.letter_id
AND y.max_date = x.date;
+-----------+-----------+------------+---------------+
| action_id | letter_id | date | action_status |
+-----------+-----------+------------+---------------+
| 2 | 101 | 2018-09-22 | Finished |
| 3 | 103 | 2018-09-16 | On-Going |
| 5 | 104 | 2018-09-27 | Finished |
+-----------+-----------+------------+---------------+
Presumably, you can figure out the rest

mysql create multiple select to put max in all rows

This is my table with sample data:
Table:PersTrans
+------------+-------------+------+-----+------------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+------------+-------+
| PersTrID | char(10) | NO | PRI | | |
| PersTrSeq | int(11) | NO | PRI | 0 | |
| PersTrDate | date | YES | | 1001-01-01 | |
| PersTrPaid | float(9,2) | YES | | 0.00 | |
+------------+-------------+------+-----+------------+-------+
mysql> select * from PersTrans;
+------------+-----------+-----------+-------------+
| PersTrID | PersTrSeq | PersTrDate | PersTrPaid |
+------------+-----------+-----------+-------------+
| MOCK | 1 | 2015-10-10 | 400.00 |
| MOCK | 2 | 2017-11-07 | 10.00 |
| NAGA | 1 | 2015-11-11 | 500.00 |
| NASSA | 1 | 2015-12-16 | 800.00 |
+------------+-----------+-----------+-------------+
I'd like to pick up the maximum PersTrSeq, and attach it to all the records that have the same PersTrId. What I want:
+------------+-----------+------------+------------+----------------+
| PersTrID | PersTrSeq | PersTrDate | PersTrPaid | max(PersTrSeq) |
+------------+-----------+-----------+------------+-----------------+
| MOCK | 1 | 2015-10-10 | 400.00 | 2 |
| MOCK | 2 | 2017-11-07 | 10.00 | 2 |
| NAGA | 1 | 2015-11-11 | 500.00 | 1 |
| NASSA | 1 | 2015-12-16 | 800.00 | 1 |
+------------+-----------+-----------+------------+-----------------+
These two attempts didn't work. I've looked for other suggestions but haven't found anything helpful.
mysql> SELECT *, max(PersTrSeq) from PersTrans where PersTransId = 'Mock' group by PersTrSeq;
+------------+-----------+------------+------------+----------------+
| PersTrID | PersTrSeq | PersTrDate | PersTrPaid | max(PersTrSeq) |
+------------+-----------+-----------+------------+-----------------+
| MOCk | 1 | 2015-10-10 | 400.00 | 1 |
| MOCK | 2 | 2017-11-07 | 10.00 | 2 |
+------------+-----------+-----------+------------+-----------------+
mysql> SELECT *, max(PersTrSeq) as maxseq from PersTrans group by PersTrId;
+------------+-----------+------------+------------+--------+
| PersTrID | PersTrSeq | PersTrDate | PersTrPaid | maxseq |
+------------+------------+-----------+------------+--------+
| MOCK | 1 | 2015-10-10 | 400.00 | 2 |
| NAGA | 1 | 2015-11-11 | 500.00 | 1 |
| NASSA | 1 | 2015-12-16 | 800.00 | 1 |
+------------+-----------+-----------+------------+---------+
Can anyone offer a single query that will get the result I'm looking for?
Following query will work:
select *,
(select max(PersTrSeq) from PersTrans p2
where p2.PersTrId = p1.PersTrId
) as maxSeq
from PersTrans p1;
If I understand what you want, you want the same number of records as the actual data, substituting the max(PersTrSeq) for all rows with a certain PersTrID.
SELECT
`PerTrID`,
(SELECT max(`PersTrSeq`) FROM `PersTrans` b WHERE b.`PersTrID = a.`PersTrID`) as `PersTrSeq`,
`PersTrDate`,
`PersTrPaid`,
from `PersTrans` a

Row to column transform

After multiple join, I have raw results.
+----------------------------------------------------------------------+
| Results |
+----+----------+-------------+----------+-----------+-----------------+
| id | group_id | question_id | question | answer_id | answer | input |
+----+----------+-------------+----------+-----------+-----------------+
| 1 | 10001 | 1 | How old | 1 | 25 | NULL |
| 2 | 10001 | 2 | What like| 3 | Cola | NULL |
| 3 | 10001 | 2 | What like| 4 | Other | HotDog |
| 4 | 10001 | 3 | City | 5 | NYC | NULL |
| 5 | 10001 | 4 | Name | 7 | Other | Alex |
| 6 | 10002 | 1 | How old | 1 | 25 | NULL |
| 7 | 10002 | 2 | What like| 6 | Candy | NULL |
| 8 | 10002 | 3 | City | 8 | LA | NULL |
| 9 | 10002 | 4 | Name | 7 | Other | Roman |
+----+----------+-------------+----------+-----------+--------+--------+
But now I want to see it in "one row view" by group_id.
Such as:
+----+----------+-------------+----------+-----------+
| id | How Old | What like | City | Name |
+----+----------+-------------+----------+-----------+
| 1 | 25 | Cola,HotDog | NYC | Alex |
| 2 | 25 | Candy | LA | Roman |
+----+----------+-------------+----------+-----------+
I don`t know normal group_by/concat construction for that. What must I do?
SET #i := 1;
SELECT #i := #i + 1 AS `id`
, GROUP_CONCAT(CASE WHEN question = 'How old' THEN answer ELSE NULL END) AS `How Old`
, GROUP_CONCAT(CASE WHEN question = 'What like' THEN IF(answer='Other', input, answer) ELSE NULL END) AS `What like`
, ....
FROM theTable
GROUP BY group_id
;
group_concat ignores null values, only returning null if the only values it received were null. For the CASE WHEN THEN ELSE END statements you could easily use IF(,,) like was used in the "other" check; but CASE is more portable (MS SQL Server only relatively recently added support for those kinds of IFs.)

How to get the sum of previous 10 rows in mysql?

Is it possible to get the sum of values in last 10 rows with respect to the current row?
I have created a database for a shop, which contains a table named purchase_details. Structure of that table is:
+--------------------------------+---------------+-----+
| Field | Type | Key |
+--------------------------------+---------------+-----+
| Trans_ID | int(11) | PRI |
| Dealer_Name | varchar(40) | |
| Todays_Purchase | double(18,10) | |
| Total_Purchase_In_Last_10_Days | double(18,10) | |
+--------------------------------+---------------+-----+
Sample data:
+----------+-------------+-----------------+--------------------------------+
| Trans_ID | Dealer_Name | Todays_Purchase | Total_Purchase_In_Last_10_Days |
+----------+-------------+-----------------+--------------------------------+
| 1 | Rahul | 7769.1488285639 | NULL |
| 2 | Rahul | 4158.5117578537 | NULL |
| 3 | Rahul | 7200.1363099802 | NULL |
| 4 | Rahul | 9338.8341269511 | NULL |
| 5 | Rahul | 5897.7252866370 | NULL |
| 6 | Rahul | 3266.6656585172 | NULL |
| 7 | Rahul | 3188.0742696276 | NULL |
| 8 | Rahul | 4270.5917314234 | NULL |
| 9 | Rahul | 2604.3369713541 | NULL |
| 10 | Rahul | 7908.6014441989 | NULL |
| 11 | Rahul | 2693.4584823737 | NULL |
| 12 | Rahul | 7945.7825034862 | NULL |
| 13 | Rahul | 1904.1472157570 | NULL |
| 14 | Rajesh | 7093.0478540344 | NULL |
| 15 | Rajesh | 3219.3736989638 | NULL |
+----------+-------------+-----------------+--------------------------------+
I want get the sum of purchases done in last 10 transactions, with the condition that there should be at least 10 transactions to sum up.
Expected output:
+----------+-------------+-----------------+--------------------------------+
| Trans_ID | Dealer_Name | Todays_Purchase | Total_Purchase_In_Last_10_Days |
+----------+-------------+-----------------+--------------------------------+
| 1 | Rahul | 7769.1488285639 | 0.0000000000 |
| 2 | Rahul | 4158.5117578537 | 0.0000000000 |
| 3 | Rahul | 7200.1363099802 | 0.0000000000 |
| 4 | Rahul | 9338.8341269511 | 0.0000000000 |
| 5 | Rahul | 5897.7252866370 | 0.0000000000 |
| 6 | Rahul | 3266.6656585172 | 0.0000000000 |
| 7 | Rahul | 3188.0742696276 | 0.0000000000 |
| 8 | Rahul | 4270.5917314234 | 0.0000000000 |
| 9 | Rahul | 2604.3369713541 | 0.0000000000 |
| 10 | Rahul | 7908.6014441989 | 55602.6263900000 |
| 11 | Rahul | 2693.4584823737 | 50526.9360400000 |
| 12 | Rahul | 7945.7825034862 | 54314.2067800000 |
| 13 | Rahul | 1904.1472157570 | 49018.2176900000 |
| 14 | Rajesh | 7093.0478540344 | 0.0000000000 |
| 15 | Rajesh | 3219.3736989638 | 0.0000000000 |
+----------+-------------+-----------------+--------------------------------+
For this, I've created a mysql function, which will take the Trans_ID and Dealer_Name as a parameter, and will return the sum of Todays_Purchase column.
Function definition:
CREATE FUNCTION GET_TOTAL_PURCHASE(paramTransID INT, paramDealerName VARCHAR(40))
RETURNS DOUBLE(18,10)
READS SQL DATA
BEGIN
DECLARE totalPurchase DOUBLE(18,10);
SET totalPurchase = 0;
SELECT SUM(Todays_Purchase)
INTO totalPurchase
FROM purchase_details
WHERE Trans_ID > (paramTransID-10)
AND Trans_ID <= paramTransID
AND Dealer_Name = paramDealerName;
RETURN totalPurchase;
END
And the SQL query to update Total_Purchase_In_Last_10_Days column is:
UPDATE purchase_details
SET Total_Purchase_In_Last_10_Days = GET_TOTAL_PURCHASE(Trans_ID, Dealer_Name);
Above SQL works properly, but it takes too much time to execute. There are more than a million records in the table, so the query takes more than 5 minutes. Hoe to improve this?
Derived information (such as what you are asking for) is properly done in SELECTs, not by having redundant code in the table.
If one user pulls up his info, it will be reasonably cheap to compute the sum on the fly. And you already have the FUNCTION to do that.
However, can you really trust Trans_ID to be consecutive, no gaps, etc? Your nomenclature is inconsistent: "_Last_10_Days" vs "previous 10 rows" versus "Trans_". "10 days" can be tricky if there are gaps. Etc.