error in my mysql query with a limit condition - mysql

i have 3 tables
customers, times and sales
i want to find out all the customers income yearly condition is that customers with no children and income must be greater than a limit we are set
my table structure
customers
CREATE TABLE `customers` (
`customer_id` int(11) DEFAULT NULL,
`account_num` double DEFAULT NULL,
`lname` varchar(50) DEFAULT NULL,
`fname` varchar(50) DEFAULT NULL,
`mi` varchar(50) DEFAULT NULL,
`address1` varchar(50) DEFAULT NULL,
`address2` varchar(50) DEFAULT NULL,
`address3` varchar(50) DEFAULT NULL,
`address4` varchar(50) DEFAULT NULL,
`postal_code` varchar(50) DEFAULT NULL,
`region_id` int(11) DEFAULT NULL,
`phone1` varchar(50) DEFAULT NULL,
`phone2` varchar(50) DEFAULT NULL,
`birthdate` datetime DEFAULT NULL,
`marital_status` varchar(50) DEFAULT NULL,
`yearly_income` varchar(50) DEFAULT NULL,
`gender` varchar(50) DEFAULT NULL,
`total_children` smallint(6) DEFAULT NULL,
`num_children_at_home` smallint(6) DEFAULT NULL,
`education` varchar(50) DEFAULT NULL,
`member_card` varchar(50) DEFAULT NULL,
`occupation` varchar(50) DEFAULT NULL,
`houseowner` varchar(50) DEFAULT NULL,
`num_cars_owned` smallint(6) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
sales
CREATE TABLE `sales` (
`product_id` int(11) DEFAULT NULL,
`time_id` int(11) DEFAULT NULL,
`customer_id` int(11) DEFAULT NULL,
`store_id` int(11) DEFAULT NULL,
`store_sales` float DEFAULT NULL,
`store_cost` float DEFAULT NULL,
`unit_sales` double DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
times
CREATE TABLE `times` (
`time_id` int(11) DEFAULT NULL,
`the_date` datetime DEFAULT NULL,
`the_day` varchar(50) DEFAULT NULL,
`the_month` varchar(50) DEFAULT NULL,
`the_year` smallint(6) DEFAULT NULL,
`day_of_month` smallint(6) DEFAULT NULL,
`month_of_year` smallint(6) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
MY question is :-Find the list of the customers with no child and an yearly_income greater that a limit given by the user when running the query.
MY query is
SET #limit=50;
SELECT customers.`fname`, customers.`lname` ,ROUND(SUM(sales.store_sales)) as income,times.the_year
FROM `sales`
LEFT JOIN times
ON sales.time_id=times.time_id
LEFT JOIN customers
ON customers.customer_id=sales.customer_id
WHERE income>#limit AND `total_children`=0
GROUP BY sales.customer_id,times.the_year
am getting this error:#1054 - Unknown column 'income' in 'where clause'

The quantity you aliased as income is an aggregate, and therefore it does not make sense to refer to it in the WHERE clause. Move this WHERE logic to a HAVING clause:
SET #limit=50;
SELECT
c.fname,
c.lname,
ROUND(SUM(s.store_sales)) AS income,
t.the_year
FROM sales s
LEFT JOIN times t
ON s.time_id = t.time_id
LEFT JOIN customers c
ON c.customer_id = s.customer_id
WHERE
total_children = 0
GROUP BY
c.customer_id,
t.the_year
HAVING
ROUND(SUM(s.store_sales)) > #limit;
Note that technically we could have used the alias in the HAVING clause:
HAVING income > #limit;
But this would not be portable to most other databases. Also, I introduced aliases into the query, which make it easier to read.

For aggreagte columns not present in the original table you should use having clause instead of where
SET #limit=50;
SELECT customers.`fname`, customers.`lname` ,ROUND(SUM(sales.store_sales)) as income,times.the_year
FROM `sales`
LEFT JOIN times
ON sales.time_id=times.time_id
LEFT JOIN customers
ON customers.customer_id=sales.customer_id
WHERE `total_children`=0
GROUP BY customers.customer_id,times.the_year
having income>#limit

income is alias name,so can't use that in where condition.
SET #limit=50;
SELECT * FROM
(
SELECT customers.`fname`, customers.`lname` ,ROUND(SUM(sales.store_sales))
as income,times.the_year
FROM `sales` LEFT JOIN times ON sales.time_id=times.time_id
LEFT JOIN customers ON customers.customer_id=sales.customer_id
WHERE `total_children`=0
GROUP BY sales.customer_id,times.the_year
)t WHERE income>#limit

Find the list of the customers with no child and an yearly_income
greater that a limit given by the user when running the query.
Are you sure you don't want a simple query like this?
SELECT *
FROM customers AS c
WHERE yearly_income > #limit -- but why is yearly_income a VarChar(50)?
AND total_children=0

Related

How to optimize MySQL query with multiple identical subqueries and multiple grouping

Problem statement
The two identical sub-queries (i.e., "a" and "b") are used to derive sub-query "n" which I further aggregate to get the final result. The response time of the query is not optimal, can anyone share some ideas to help optimize? I tried to comebine "a" and "b" as well as "a" and "n" but neither turns out to be dead ends per my knowledge...
select n.businessLiaision,
n.channel,
n.name,
n.dt,
n.ifNew,
count(n.productRowId),
sum(n.totalQty),
sum(n.totalAmount)
from ( select a.productRowId,
a.name,
a.rowId,
a.dt,
a.businessLiaision,
a.channel,
a.ct,
a.totalQty,
a.totalAmount,
case when a.ct = sum(b.ct) then 'true' else 'false' end as 'ifNew'
from ( select d.productRowId,
p.name,
DATE_FORMAT(o.effectiveTime, '%m/%Y') as 'dt',
p.rowId,
p.businessLiaision,
p.channel,
count(*) as 'ct',
sum(d.qty) as 'totalQty',
sum(d.amountPostDiscount) as 'totalAmount'
from transactionParty as p
join transactionOrderHist as o on p.rowId = o.transactionPartyRowId
join transactionOrderDetailHist as d on o.rowId = d.orderRowId
where o.businessType = 'sales'
group by d.productRowId, p.name, DATE_FORMAT(o.effectiveTime, '%m/%Y'), p.rowId, p.businessLiaision, p.channel
) as a
left join ( select d.productRowId,
p.name,
DATE_FORMAT(o.effectiveTime, '%m/%Y') as 'dt',
count(*) as 'ct'
from transactionParty as p
join transactionOrderHist as o on p.rowId = o.transactionPartyRowId
join transactionOrderDetailHist as d on o.rowId = d.orderRowId
where o.businessType = 'sales'
group by d.productRowId, p.name, DATE_FORMAT(o.effectiveTime, '%m/%Y')
) as b on b.productRowId = a.productRowId and b.name = a.name and b.dt <= a.dt
group by a.productRowId, a.name, a.rowId, a.dt, a.ct, a.businessLiaision, a.channel, a.ct, a.totalQty, a.totalAmount
) as n
group by n.businessLiaision, n.channel, n.name, n.dt, n.ifNew
Explain plan result
enter image description here
Table descriptions
transactionParty
CREATE TABLE `transactionParty` (
`rowId` varchar(50) NOT NULL,
`name` varchar(100) DEFAULT NULL,
`code` varchar(20) DEFAULT NULL,
`businessLiaision` varchar(20) DEFAULT NULL,
`type` varchar(20) DEFAULT NULL,
`contractualType` varchar(20) DEFAULT NULL,
`paymentMethod` varchar(20) DEFAULT NULL,
`partyGroup` varchar(20) DEFAULT NULL,
`channel` varchar(20) DEFAULT NULL,
`costCenter` varchar(20) DEFAULT NULL,
`warehouseRowId` varchar(100) DEFAULT NULL,
`taxOption` varchar(20) DEFAULT NULL,
PRIMARY KEY (`rowId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
transactionOrderHist
CREATE TABLE `transactionOrderHist` (
`rowId` varchar(50) NOT NULL COMMENT '明道记录ID',
`orderId` varchar(50) DEFAULT NULL COMMENT '单据ID',
`orderCreationTime` datetime DEFAULT NULL COMMENT '单据创建时间',
`orderCreator` varchar(20) DEFAULT NULL COMMENT '单据创建人',
`businessType` varchar(20) DEFAULT NULL COMMENT '业务类型',
`businessLiaision` varchar(20) DEFAULT NULL COMMENT '内部业务负责人,如业务员/采购/文员',
`transactionPartyRowId` varchar(50) DEFAULT NULL COMMENT '往来单位',
`outboundWarehouse` varchar(50) DEFAULT NULL COMMENT '发货仓',
`inboundWarehouse` varchar(50) DEFAULT NULL COMMENT '收货仓',
`outboundWarehouseType` varchar(50) DEFAULT NULL,
`inboundWarehouseType` varchar(50) DEFAULT NULL,
`effectiveTime` datetime DEFAULT '0000-00-00 00:00:00' COMMENT '单据过账时间',
`orderEffectuater` varchar(20) DEFAULT NULL COMMENT '单据过账人',
`remark` varchar(200) DEFAULT NULL,
`productCount` int(10) DEFAULT NULL,
`totalUnitCount` int(10) DEFAULT NULL,
`totalCostAmount` decimal(10,0) DEFAULT NULL,
`totalPostDiscountAmount` decimal(10,0) DEFAULT NULL,
`paymentStatus` varchar(50) DEFAULT NULL,
`paymentDate` datetime DEFAULT NULL,
`outboundWarehouseRowId` varchar(50) DEFAULT NULL,
`inboundWarehouseRowId` varchar(50) DEFAULT NULL,
PRIMARY KEY (`rowId`) USING BTREE,
KEY `orderEffectiveDate` (`effectiveTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
transactionOrderDetailHist
CREATE TABLE `transactionOrderDetailHist` (
`rowId` varchar(50) NOT NULL,
`orderRowId` varchar(50) DEFAULT NULL,
`productRowId` varchar(50) DEFAULT NULL,
`qty` int(20) DEFAULT NULL,
`price` decimal(20,2) DEFAULT NULL,
`cost` decimal(20,2) DEFAULT NULL,
`amount` decimal(20,2) DEFAULT NULL,
`amountPostDiscount` decimal(20,2) DEFAULT NULL,
`type` varchar(50) DEFAULT NULL,
`effectiveTime` datetime DEFAULT NULL,
`costAmount` decimal(20,2) DEFAULT NULL,
PRIMARY KEY (`rowId`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8
FROM ( SELECT ... )
[LEFT] JOIN ( SELECT ... ) ON ...
is notoriously inefficient. Try to rewrite the query to avoid such.
Please provide EXPLAIN SELECT ...; meanwhile, I will do some guessing.
These indexes may help:
d: INDEX(orderRowId, productRowId, qty, amountPostDiscount)
o: INDEX(businessType, transactionPartyRowId, effectiveTime, rowId)
Looking at the final GROUP BY. It does not necessarily order the rows. If you want a particular order, add an ORDER BY. Be aware that the dt part is not quite in chronological order since it has month before year. The other group-bys are in derived tables, so an ORDER BY would be ignored.
If and b.name = a.name and b.dt <= a.dt is for doing "groupwise-max", that is the performance bottleneck. There are much better ways to do it. See Groupwise-Max .
If the text is in Chinese, you should consider converting to utf8mb4 -- utf8 is missing the 4-byte UTF-8 Chinese characters.
It is OK to have the PRIMARY KEY as VARCHAR(50), but it could be better to use INT. Is some outside process providing the rowId?

Creating a summary from two tables?

I have two tables and I'm trying to create a summary with the sum of amount due per person but don't have the creative ID involved.
Table 1:
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`Name` varchar(255) NOT NULL,
`Lname` varchar(255) NOT NULL,
`phone` varchar(15) NOT NULL,
`address` varchar(255) DEFAULT NULL,
`city` varchar(255) NOT NULL,
`state` char(2) NOT NULL,
`zip` varchar(50) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`business_name varchar(255) DEFAULT NULL,
Second table:
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`C_ID` INT(10) UNSIGNED NOT NULL,
`Amount_Due` DECIMAL(7 , 2 ) not null DEFAULT 0,
`created_date` DATETIME NOT NULL,
`closed_date` DATETIME default NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=LATIN1;
Here is what I'm trying to do:
I'm trying to make a summary with dates within 5/1/18 and 6/15/18.
Have the sum of due amount for each person
Have these aliases : Business name, Phone Number ,Invoiced Amounts
I'm trying to test my code but i'm getting errors:
SELECT Name,phone,SUM(Amount_Due) FROM test_customer,test_invoices
WHERE created_date BETWEEN '2018-05-01' AND "2018-06-15'
If I understand correctly, you need to use JOIN instead of ,(CROSS JOIN) and GROUP BY in non-aggregate function columns.
SELECT Name 'Customer Name',
phone 'Phone number',
SUM(i.Amount_Due) 'Amount due'
FROM test_customer c
INNER JOIN test_invoices i ON C.id = i.C_ID
GROUP BY Name,phone
sqlfiddle

How can I calculate rank based on highest Score and lowest Minutes in MySql

CREATE TABLE IF NOT EXISTS `teststatus` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`userid` int(11) DEFAULT NULL,
`duration` varchar(45) DEFAULT NULL,
`starttime` varchar(20) DEFAULT NULL,
`endtime` varchar(20) DEFAULT NULL,
`totaltime` varchar(70) DEFAULT NULL,
`totaltime_minutes` varchar(70) DEFAULT NULL,
`totalquestions` varchar(20) DEFAULT NULL,
`correctlyanswered` int(11) DEFAULT NULL,
`status` varchar(10) DEFAULT NULL,
`totalmarks` int(11) DEFAULT NULL,
`emailid` varchar(100) DEFAULT NULL,
`requesttoken` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
)
I have tried to excute this query.
SELECT d.userid, d.totaltime, d.totalmarks, d.emailid, c.ranks
FROM
(
SELECT totalmarks, #rank:=#rank+1 Ranks
FROM
(
SELECT DISTINCT totalmarks
FROM teststatus
ORDER BY totalmarks DESC
) t,
(
SELECT #rank:= 0
) r
) c
INNER JOIN teststatus d
ON c.totalmarks = d.totalmarks
ORDER BY ranks;
but it shows rank based on totalmarks but i want rank based on maximum marks and less totaltime.
Result i am getting:
totaltime,totalmarks,ranks
150,13,1
180,12,2
110,11,3
100,11,3
105,11,3
80,11,3
120,11,3
90,11,3
140,9,4
112,8,5
145,8,5
120,7,6
157,7,6
120,6,7

MySQL - Counting a count?

I'm trying to aggregate some data I've pulled from my MySQL db.
Query I'm using is:
SELECT `PUID`,`DROID_V`,`SIG_V`,`SPEED`,
COUNT(distinct IF(sourcelist.hasExtension=1,NAME,NULL)) as Ext,
COUNT(distinct IF(sourcelist.hasExtension=0,NAME,NULL)) as NoExt,
COUNT(distinct NAME) as `All`
FROM sourcelist, main_small
WHERE sourcelist.SourcePUID = 'My_Variable' AND main_small.NAME = sourcelist.SourceFileName
GROUP BY `PUID`,`DROID_V`,`SIG_V`,`SPEED` ORDER BY `DROID_V` ASC, `SIG_V` ASC, `SPEED`
And I wondered if there was a way of counting this result, so I can make a new table that would show me something like:
Every distinct PUID, (count of distinct DROID_V), (count of distinct Sig_V), (SUM of total hits for NAME) WHERE sourcelist.SourcePUID = 'My_Variable' AND main_small.NAME = sourcelist.SourceFileName
As you can see, I'm really not very good at SQL!
Source table:
CREATE TABLE `t1` (
`DROID_V` int(1) DEFAULT NULL,
`Sig_V` varchar(7) DEFAULT NULL,
`SPEED` varchar(4) DEFAULT NULL,
`ID` varchar(7) DEFAULT NULL,
`PARENT_ID` varchar(10) DEFAULT NULL,
`URI` varchar(10) DEFAULT NULL,
`FILE_PATH` varchar(68) DEFAULT NULL,
`NAME` varchar(17) DEFAULT NULL,
`METHOD` varchar(10) DEFAULT NULL,
`STATUS` varchar(14) DEFAULT NULL,
`SIZE` int(10) DEFAULT NULL,
`TYPE` varchar(10) DEFAULT NULL,
`EXT` varchar(4) DEFAULT NULL,
`LAST_MODIFIED` varchar(10) DEFAULT NULL,
`EXTENSION_MISMATCH` varchar(32) DEFAULT NULL,
`MD5_HASH` varchar(10) DEFAULT NULL,
`FORMAT_COUNT` varchar(10) DEFAULT NULL,
`PUID` varchar(15) DEFAULT NULL,
`MIME_TYPE` varchar(24) DEFAULT NULL,
`FORMAT_NAME` varchar(10) DEFAULT NULL,
`FORMAT_VERSION` varchar(10) DEFAULT NULL,
`INDEX` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`INDEX`)
) ENGINE=MyISAM AUTO_INCREMENT=960831 DEFAULT CHARSET=utf8
example records:
5;"v37";"slow";"10266";;"file:";"V1-FL425817.tif";"V1-FL425817.tif";"BINARY_SIG";"MultipleIdenti";"20603284";"FILE";"tif";"2008-11-03";;;;"fmt/7";"image/tiff";"Tagged Ima";"3";"191977"
5;"v37";"slow";"10268";;"file:";"V1-FL425817.tif";"V1-FL425817.tif";"BINARY_SIG";"MultipleIdenti";"20603284";"FILE";"tif";"2008-11-03";;;;"fmt/8";"image/tiff";"Tagged Ima";"4";"191978"
5;"v37";"slow";"10269";;"file:";"V1-FL425817.tif";"V1-FL425817.tif";"BINARY_SIG";"MultipleIdenti";"20603284";"FILE";"tif";"2008-11-03";;;;"fmt/9";"image/tiff";"Tagged Ima";"5";"191979"
5;"v37";"slow";"10270";;"file:";"V1-FL425817.tif";"V1-FL425817.tif";"BINARY_SIG";"MultipleIdenti";"20603284";"FILE";"tif";"2008-11-03";;;;"fmt/10";"image/tiff";"Tagged Ima";"6";"191980"
Sure just do something like
Select Count(*) From (Select * From SomeTable) adummynamesoSqlParserDoesntgetupset
so put your query in parentheses after FROM give it a unique name, and you can treat it like a table or a view.

sql statement mysql notcorrect

SELECT SUBSTRING(m.own,3,4) as c , (select amphur.AMPHUR_NAME where c = SUBSTRING(m.own,3,4) ),
COUNT(* ) AS cnt
FROM MEMBER AS m
GROUP BY SUBSTRING(m.own,3,4)
order by cnt desc
sql statement mysql
what wrong with code below when i fill
(select amphur.AMPHUR_NAME where c = SUBSTRING(m.own,3,4) )
it error
CREATE TABLE IF NOT EXISTS `member` (
`idmember` int(11) NOT NULL AUTO_INCREMENT,
`own` varchar(255) DEFAULT NULL,
`Sname` varchar(255) DEFAULT NULL,
`Ssurname` varchar(255) DEFAULT NULL,
`Sex` enum('¿','¿') NOT NULL,
`Hno` varchar(255) DEFAULT NULL,
`Moo` varchar(255) DEFAULT NULL,
`tambol` varchar(200) NOT NULL,
`dateofbirth` date DEFAULT NULL,
`migratedate` date DEFAULT NULL,
`status` enum('5','4','3','2','1') DEFAULT '5',
`Unit` int(4) DEFAULT NULL,
`staff1` int(11) DEFAULT NULL,
`staff2` int(11) DEFAULT NULL,
`fathercode` varchar(30) NOT NULL,
`mathercode` varchar(30) NOT NULL,
PRIMARY KEY (`idmember`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=8994 ;
CREATE TABLE IF NOT EXISTS `amphur` (
`AMPHUR_ID` int(5) NOT NULL AUTO_INCREMENT,
`AMPHUR_CODE` varchar(4) COLLATE utf8_unicode_ci NOT NULL,
`AMPHUR_NAME` varchar(150) COLLATE utf8_unicode_ci NOT NULL,
`GEO_ID` int(5) NOT NULL DEFAULT '0',
`PROVINCE_ID` int(5) NOT NULL DEFAULT '0',
`province_name` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`AMPHUR_ID`),
KEY `province_name` (`province_name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=999 ;
Your subquery is missing a From clause:
SELECT SUBSTRING(m.own,3,4) as c
, (select amphur.AMPHUR_NAME
From amphur
Where ??? = SUBSTRING(m.own,3,4) )
, COUNT(* ) AS cnt
FROM MEMBER AS m
However, how does the amphur table relate to the member table?
You cannot use aliases in the same level.
Even if you could, you are filtering on non-correlated columns in your subquery: the subquery would just return the record from amphur if there is one record, or an error if there are more.
Could you please provide some sample data and the desired recordset?
there is no "FROM" clause in your select Amphur.amphur_name