Getting datas from multiple table in one crystal report - mysql

I got 2 tables tbl_issued and tbl_transaction.
tbl_issued has its columns, ItemID,Item,Serial,Quantity and Size. While tbl_transaction has its columns Released,Received,Approved and Department
My problem is I want to get their columns in 1 query, this is mysql query
SELECT `ItemID`,`Item`,`Serial`,`Quantity`,`Size`,`Class`,`Unit`,(SELECT `Released` FROM `tbl_transaction` WHERE `TransactionID` = 12458952) AS `Released`,
(SELECT `Received` FROM `tbl_transaction` WHERE `TransactionID` = 12458952) AS `Received`,
(SELECT `Approved` FROM `tbl_transaction` WHERE `TransactionID` = 12458952) AS `Aprroved`,
(SELECT `Department` FROM `tbl_transaction` WHERE `TransactionID` = 12458952) AS `Department`
FROM `tbl_issued` WHERE `TransactionID` = 12458952
but transferring this on vb.net does not provide output.
Any ideas how i will translate this query to vb.net? Thanks in advance for help!

I don't know what you are trying to do but if you want it to be simplified, here's how. Have you tried Inner Joins? It's like this.
SELECT ItemID, Item, Serial, Quantity, Size, Class, Unit, Released, Received,
Approved, Deparment from tbl_issued a INNER JOIN tbl_transaction b on
a.TransactionID = b.TransactionID Where a.TransactionID = 12458952
I assume that both tables have TransactionID based on your query.

Related

Error Code: 1054. Unknown column in 'on clause'

The query is meant to return the percentage based on value from one table being divided by the value of another table. However, there is something wrong and I am missing it.
similar problems noted on the board looked related to JOIN, but did not seem to be the problem, when I tried and explicit join -- basically mysql was like -- now you are an idiot-- I must have did that wrong or that is not the problem.
SELECT (pathogenPop / locationpop) as PercentInfected
FROM (
(SELECT apinfectcount.APInfectCountInfected
as pathogenPop, apinfectcount.APInfectCountLocation
FROM apstart.apinfectcount
GROUP BY apinfectcount.APInfectCountLocation) as pathogenPop
Inner JOIN
(SELECT apcountrypop.apcountrypopPopulation
as locationpop, apcountrypop.apcountrypopCountry
FROM apstart.apcountrypop
GROUP BY apcountrypop.apcountrypopCountry)
as locationpop
on apinfectcount.APInfectCountLocation = apcountrypop.apcountrypopCountry
and apinfectcount.APInfectCountWeek = 23);
Table Schema: apcountrypop
idapcountrypop INT(11)
apcountrypopCountry VarChar(45)
apcountrypopPopulation FLOAT
Table Schema: apinfectcount
idAPInfectCount INT(11)
APInfectCountLocation VarChar(45)
APInfectCountOutBreak VarChar(45)
APInfectCountPathogen VarChar(45)
APInfectCountInfected FLOAT
APInfectCountDead FLOAT
APInfectCountWeek VarChar(45)
If it worked --
it would assign apinfectcount.APInfectCountInfected to pathogenPop
and apcountrypop.apcountrypopPopulation to locationpop
for the values where the locations are the same(apinfectcount.APInfectCountLocation = apcountrypop.apcountrypopCountry)
then it would return the value of the apinfectcount table value is divided by the apcountrypop table to give the percentage.
so in this specific example I only have sample data so I am just wanted to return one value so I added the where clause to just test the logic and syntax.
I appreciate the help.
You have assugned the tables alias pathogenPop and locationpop so
you need pathogenPop.APInfectCountLocation = locationpop.apcountrypopCountry
and pathogenPop.APInfectCountWeek = 23 in ON clause
SELECT (pathogenPop / locationpop) as PercentInfected
FROM (
(SELECT apinfectcount.APInfectCountInfected
as pathogenPop, apinfectcount.APInfectCountLocation
FROM apstart.apinfectcount
GROUP BY apinfectcount.APInfectCountLocation) as pathogenPop
Inner JOIN
(SELECT apcountrypop.apcountrypopPopulation
as locationpop, apcountrypop.apcountrypopCountry
FROM apstart.apcountrypop
GROUP BY apcountrypop.apcountrypopCountry)
as locationpop
on pathogenPop.APInfectCountLocation = locationpop.apcountrypopCountry
and pathogenPop.APInfectCountWeek = 23) T;
and also a table alias for the outer FROM(..) T
I don't have the database to test against so I'm not 100% certain this will run, but would the following query not be a bit simpler?
SELECT (apinfectcount.APInfectCountInfected / apcountrypop.apcountrypopPopulation) as PercentInfected, apinfectcount.APInfectCountLocation
FROM apinfectcount
INNER JOIN apcountrypop ON apcountrypop.apcountrypopCountry = apinfectcount.APInfectCountLocation
WHERE apinfectcount.APInfectCountWeek = 23
GROUP BY apinfectcount.APInfectCountLocation
And I assume there is only one location record per location in each table?
There is an issue within a query. As scope of apinfectcount.APInfectCountLocation column and apcountrypop.apcountrypopCountry column is limited to subquery only you cannot use it outside the subquery (within where clause).
You can check out these docs on subquery https://learn.microsoft.com/en-us/sql/relational-databases/performance/subqueries?view=sql-server-2017
Refer code below.
SELECT (countInfected / countrypopulation) as PercentInfected
FROM (
(SELECT apinfectcount.APInfectCountInfected
as countinfected, apinfectcount.APInfectCountLocation, APInfectCountWeek as
countweek
FROM apstart.apinfectcount
GROUP BY apinfectcount.APInfectCountLocation) as pathogenPop
Inner JOIN
(SELECT apcountrypop.apcountrypopPopulation
as countrypopulation, apcountrypop.apcountrypopCountry
FROM apstart.apcountrypop
GROUP BY apcountrypop.apcountrypopCountry)
as locationpop
on pathogenPop.countinfected = locationpop.countrypopulation
and pathogenPop.countweek= 23);

Improve Efficiency Of This Query: Update With Joins and Subqueries

I have a mysql database with
- table of Parcels which need to be sent to people (here 16,000 records),
indexes on account_no, service
- table of Price Rates (500,000 records) - rate depends on: delivery area, customer price rate and type of service(e.g. next day etc), indexes
on area, price rate, service
- table of first part of postcode (or zip Code), which gives area (3000)
- table of customer account, containing price rate (1600), index on price rate
The query finds the price it will cost to send the parcel and updates the customer price for that parcel with unique id
It is taking 70 seconds for 16000 parcel records to be updated with the price to send each parcel
UPDATE
tbl_parcel AS t20, (
SELECT
id, service, rate_group, area,
(
SELECT
rate
FROM
tbl_rates_all t4
WHERE
t4.service = t10.service
AND t4.area = t10.area
AND t4.rate_group = t10.rate_group
)
AS price
FROM
(
SELECT
id,
t1.service,
rate_group,
area
FROM
tbl_parcel t1
JOIN
tbl_account t2
ON t1.account_no = t2.account_no
JOIN
tbl_pr_postcode t3
ON LEFT(full_pcode, locate(' ', full_pcode) - 1) = t3.postcode
) t10
) AS src
SET
t20.customer_price = src.price
WHERE
t20.id = src.id
Takes 70 seconds for the 16000 parcel records
Ultimately it is this part that is killing the efficiency
FROM
tbl_rates_all t4
WHERE
t4.service = t10.service
AND t4.area = t10.area
AND t4.rate_group = t10.rate_group
I could have separate rates tables for each rate as this was the original design so a variable would call e.g. tbl_rates001 which might only have 3000 records and not 500,000. Problem with doing this in mysql was when creating a table name on the fly it was not possible without using a prepared statement so i thought this method was no good. Shame you couldn't use a user variable to hold the price rate number and then add this to the table rate name.
I'm quite new to databases and queries so if something is screaming at you that would help then thanks for any input
regards
ADDTION AS REQUESTED SCHEMA
CREATE TABLE `tbl_x_rate_all` (
`id` bigint(20) NOT NULL,
`service` varchar(4) NOT NULL,
`chargetype` char(1) NOT NULL,
`area` smallint(6) NOT NULL,
`rate` float(7,2) NOT NULL,
`rate_group` smallint(6) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
ALTER TABLE `tbl_x_rate_all` ADD PRIMARY KEY (`id`), ADD KEY `rate_group` (`rate_group`), ADD KEY `area` (`area`), ADD KEY `service` (`service`),
ADD KEY `chargetype` (`chargetype`);
Assuming id, rate_group and area are from t1 inside t10 then your query is a slower? version of the one below:
UPDATE
tbl_parcel AS t20
INNER JOIN (
SELECT
t1.id,
t4.rate as price
FROM tbl_parcel t1
JOIN tbl_account t2 ON t1.account_no = t2.account_no
JOIN tbl_pr_postcode t3 ON LEFT(full_pcode, locate(' ', full_pcode) - 1) = t3.postcode
LEFT JOIN tbl_rates_all t4 ON t1.service = t4.service AND t1.area = t4.area
AND t1.rate_group = t4.rate_group
) src ON t20.id = src.id
SET
t20.customer_price = src.price
WHERE
t20.id = src.id
I am guessing you can further lose the subquery which tend to be cumbersome:
UPDATE
tbl_parcel AS t20
INNER JOIN tbl_parcel t1 ON t20.id = t1.id
INNER JOIN tbl_account t2 ON t1.account_no = t2.account_no
INNER JOIN tbl_pr_postcode t3 ON LEFT(full_pcode, locate(' ', full_pcode) - 1) = t3.postcode
LEFT JOIN tbl_rates_all t4 ON t1.service = t4.service AND t1.area = t4.area
AND t1.rate_group = t4.rate_group
SET
t20.customer_price = t4.rate
WHERE
t20.id = t1.id
-- can also replace with
-- TRUE
-- or lose it altogether
;
You could try adding index on joins of t1 and t4 if you have reason to believe that the join is the bottleneck:
create index tbl_rates_all_service_area_rate_group_index
on tbl_rates_all (service, area, rate_group);
create index tbl_parcel_service_area_rate_group_index
on tbl_parcel (service, area, rate_group);
#Rich --
Nothing's jumping out. You might be able to get some marginal improvements by building some temp tables, handling the SET outside your main query, and using some OUTER APPLY instead of the nested queries.
If you're fairly new to mysql / databases in general, the EXPLAIN function can be very useful in optimization
https://dev.mysql.com/doc/refman/5.5/en/using-explain.html

MySQL find results based on two different values of the same column

list employees names (Ename) who have both 49008 zip code customers and 49009 zip code customers.
I am struggling to answer the above query based on the above tables.
If the names match between tables assume constraint.
I can filter down to name and zip easily by left joins and group by but struggle after that, I don't know the proper where or having statement. I am assuming it could be done better by a sub query but not sure. Ideally, a single query.
Please and thank you.
1) Create and insert statements for example data:
Create table Employees (EM_Eno INT NOT NULL, EM_Ename VARCHAR(50), EM_Hire_Date DATE, PRIMARY KEY(EM_Eno));
Create table Customers (Customers_Cno INT NOT NULL, Customers_Cname VARCHAR(50), Customers_Street VARCHAR(50), Customers_Zip INT, Customers_Phone INT, primary key(Customers_Cno));
Create table Orders (Orders_Ono INT NOT NULL, Orders_Cno INT, Orders_Eno INT, Orders_Received DATE, Orders_Shipped DATE, primary key(Orders_Ono));
insert into Orders values
( 1,301,501,20161010,20161011);
( 2,302,501,20161011,20161012);
( 3,303,502,20161110,20161111);
( 4,304,502,20161110,20161112);
( 5,305,502,20161110,20161113);
( 6,306,503,20161112,20161114);
( 7,307,501,20161112,20161113);
( 8,308,503,20161112,20161115);
( 9,309,503,20161115,20161120);
(10,300,501,20161112,20161113);
insert into Customers values
(300,'Bryan','100 street',49009,1234567890),
(301,'Ryan','101 street',49008,1234567890),
(302,'Nick','102 street',49009,1234567890),
(303,'Nicholas','103 street',49009,1234567890),
(304,'Alexa','104 street',49009,1234567890),
(305,'Tori','105 street',49008,1234567890),
(306,'Scarlet','106 street',49008,1234567890),
(307,'Heather','100 street',49009,1234567890),
(308,'Amanda','107 street',49008,1234567890),
(309,'James','108 street',49008,1234567890);
insert into Employees values
(501,'Robert',20041010),
(502,'Sam',20050110),
(503,'Brandy',20050710);
2) Ideal end result is answering the query "list employees (names) who have both 49008-zipcode customers and 49009-zipcode customers."
3) Best Attempt thus far:
select Employees.EM_Ename
, Customers.Customers_Zip
from Employees
left
join Orders
on Employees.EM_Eno = Orders.Orders_Eno
left
join Customers
on Orders.Orders_Cno = Customers.Customers_Cno
group
by Employees.EM_Ename
, Customers.Customers_Zip;
The table names are altered slightly in the rextest, because other tables already exist there with the same name...
SELECT e.*
FROM tbl_employees e
JOIN tbl_orders o
ON o.orders_eno = e.em_eno
JOIN tbl_customers c
ON c.Customers_Cno = o.Orders_Cno
WHERE c.Customers_Zip IN(49008,49009)
GROUP
BY e.em_eno
HAVING COUNT(DISTINCT customers_zip) = 2;
http://rextester.com/HCNLU51847
This should be what you want:
select Min(e.Ename)
from #Employees e
join #Orders o on o.Eno = e.Eno
join #Customers c on c.Cno = o.Cno
join #Orders o2 on o2.Eno = e.Eno
join #Customers c2 on c2.Cno = o2.Cno
where o.Ono !=o2.Ono--c.Cno != c2.Cno and
and c.Zip = 49008 and c2.Zip = 49009
group by e.Ename,c.Zip
order by e.Ename
As you can see if you wanted more than those two the self joins become longer.

MySQL Database design advice - using joins

I am building an AJAX like search page which allows a customer to select a number filters that will narrow down the search. For instance, a user has selected an 'iPhone 5' and has additional filters for capacity (32GB, 64GB) & colour (black, white..).
The user can only select a single radio box per category (so they could select 32GB & Black).. but they could not select (32GB & 64GB & black as two of these belong to the 'capacity' category).
I have added the schema here on sqlfiddle (please ignore the fact i've removed the primary keys they exist in the proper app they have just been removed along with some other fields/data to minimise the sqlfiddle)
http://sqlfiddle.com/#!2/964425
Can anyone suggest the best way to create the query to do the following:
Get all the prices for device_id '2939' (iPhone 5) which has the 'attributes' of '32GB' AND 'Black'
I currently have this - but this only works when selecting for a single attribute:
// search for device with '64GB' & 'Black' attributes (this currently doesn't return any rows)
SELECT `prices`.*
FROM (`prices`)
LEFT JOIN `prices_attributes` ON `prices_attributes`.`price_id` = `prices`.`id`
WHERE `prices`.`device_id` = '2939'
AND `attribute_option_id` = '19'
AND `attribute_option_id` = '47';
// search for device with '64GB' attribute only (this currently DOES return a row)
SELECT `prices`.*
FROM (`prices`)
LEFT JOIN `prices_attributes` ON `prices_attributes`.`price_id` = `prices`.`id`
WHERE `prices`.`device_id` = '2939'
AND `attribute_option_id` = '19';
Any advice on the database design would be appreciated too
Note: I was thinking to have a new column within the 'prices' table that has the matching attribute_ids serialised - would this be not good for optimisation however (e.g would it be slower than the current method)
Since attribute_option_id is an atomic value, it cannot have two different values for the same row. So your WHERE clause cannot match any record:
SELECT `prices`.*
FROM (`prices`)
LEFT JOIN `prices_attributes` ON `prices_attributes`.`price_id` = `prices`.`id`
WHERE `prices`.`device_id` = '2939'
AND `attribute_option_id` = '19' # Here for one row, attribute_option_id is either 19
AND `attribute_option_id` = '47'; # of '47'. Cannot be the both
Instead of JOIN, you could try a subquery if you feel that is more readable. I think MySQL allow that syntax:
SELECT `prices`.*
FROM `prices`
WHERE `prices`.`device_id` = '2939'
AND EXISTS (SELECT *
FROM prices_attributes
WHERE price_id = `prices`.`id`
AND attribute_option_id IN ('19', '47') )
I don't know how MySQL will optimize the above solution. An alternative would be:
SELECT `prices`.*
FROM `prices`
WHERE `prices`.`id` IN (
SELECT DISTINCT `price_id`
FROM prices_attributes
WHERE attribute_option_id IN ('19', '47')
)
I think you should use the IN operator for the attribute_option_id and you set the values dynamically to the query; Also, using group_by you have only one row per price so in effect you get all the prices. Apart from this, the design is ok.
Here, I have made an example:
SELECT `prices`.*
FROM (`prices`)
LEFT JOIN `prices_attributes` ON `prices_attributes`.`price_id` = `prices`.`id`
WHERE `prices`.`device_id` = '2939'
and `attribute_option_id` in ('19','47')
group by `prices`.`device_id`, `prices`.`price`;
Here, you can also add an order clause to order by price:
order by `prices`.`price` desc;
Another way to solve this would be to use a distinct on price, like this:
select distinct(prices.price)
from prices
where prices.device_id = 2939
and id in (select price_id from prices_attributes where attribute_option_id in (19,47));
Join against the devices_attributes_options table several times, once for each attribute the item must have
Something like this:-
SELECT *
FROM devices a
INNER JOIN prices b ON a.id = b.device_id
INNER JOIN prices_attributes c ON b.id = c.price_id
INNER JOIN devices_attributes_options d ON c.attribute_option_id = d.id AND d.attribute_value = '32GB'
INNER JOIN devices_attributes_options e ON c.attribute_option_id = e.id AND e.attribute_value = 'Black'
WHERE a.id = 2939
As to putting serialised details into a field, this is a really bad idea and would come back to bite you in the future!
SELECT * FROM prices WHERE device_id=2939 AND id IN (SELECT price_id FROM prices_attributes WHERE attribute_option_id IN (19,47));
Is it what you're looking for?
EDIT: sorry, didn't notice you're asking for query using joins

Using JOIN and SUM returns unwanted null row when WHERE condition is not met

Please consider the following query:
Select all payments of a user and UNION the results with the user's invoices.
SELECT `id`,
`amount` AS `value`,
'PAYMENT' AS `transaction_type`
FROM `payment`
WHERE `user_id` = $user_id
UNION ALL
SELECT `i`.`id`,
(-1) * SUM(`ii`.`unit_price` * `ii`.`quantity`) AS `value`,
'INVOICE' AS `transaction_type`
FROM `invoice` `i`
JOIN `invoiceitem` `ii` ON `ii`.`invoice_id` = `i`.`id`
WHERE `user_id` = $user_id AND `type` = 'invoice'
The problem is that for users that have no payment and no invoice, an unwanted row is returned like this:
id | value | transaction_type
=================================
NULL | 0 | NULL
But for users that have some data, the result is completely expected.
IMPORTANT EDIT
After some more research, I got that the problem should be from the second subquery below:
SELECT i.id,
(-1) * SUM(ii.unit_price * ii.quantity) AS `value`,
'INVOICE' AS `trans_type`
FROM invoice i
JOIN invoiceitem ii ON ii.invoice_id = i.id
WHERE user_id = 4 AND type = 'invoice'
which returns the following:
id | value | transaction_type
=================================
NULL | NULL | INVOICE
Of course the user with user_id = 4 has not yet any invoice. But for another user that has some invoices, the result is OK.
This row is created by the aggregate function SUM. In order to prevent this, use a valid GROUP BY clause, probably GROUP BY user_id
It's impossible to say with any certainty without understanding the complete table descriptions, but based on the update to your question, you need to eliminate rows that have NULL values for the column i.id:
SELECT i.id
, (-1) * SUM(ii.unit_price * ii.quantity) AS `value`
, 'INVOICE' AS `trans_type`
FROM invoice i
JOIN invoiceitem ii
ON ii.invoice_id = i.id
WHERE user_id = 4
AND type = 'invoice'
AND i.id IS NOT NULL
I'm guessing that there is a logical defect in your data model or there might be some other column you should use. I can speculate that this invoice row could be a cancelled order, but it is clear that a row exists where the id column is null, which is why it appears in the result.
To avoid such nulls just use a LEFT JOIN instead of INNER JOIN, so, replace your following sql line:
JOIN `invoiceitem` `ii` ON `ii`.`invoice_id` = `i`.`id`
for this one:
LEFT OUTER JOIN `invoiceitem` `ii` ON `ii`.`invoice_id` = `i`.`id`