SQL debug - where condition ignored - mysql

Can somebody explain me this. My SQL:
SELECT
`offers`.`id`,
`offers`.`max_available`,
(SELECT COUNT( coupons.id ) FROM coupons WHERE coupons.status = 'Y' AND coupons.offer_id = offers.id) AS coupons_sold
FROM
`offers`
WHERE
`offers`.`status` IN ('P', 'S') AND
`offers`.`published_at` < 1341612000 AND
`offers`.`end_at` >1341567914 AND
`coupons_sold` < `offers`.`max_available`
ORDER BY `offers`.`created_at` DESC
LIMIT 4 OFFSET 0
This will return me these 4 rows:
id max_available coupons_sold
195 19 20
194 9999 0
193 9999 0
159 9999 93
How is possible that row with ID 195 is included, if I have this condition in where coupons_sold < offers.max_available? I am clueless!

This query would produce an error, as you can't use in WHERE clause, an alias from the SELECT list. Unless table offers has a coupons_sold column, too!
Try this query, instead:
SELECT id, max_available, coupons_sold
FROM
( SELECT
`offers`.`id`,
`offers`.`max_available`,
( SELECT COUNT( coupons.id )
FROM coupons
WHERE coupons.status = 'Y'
AND coupons.offer_id = offers.id
) AS coupons_sold
offers.created_at
FROM
`offers`
WHERE
`offers`.`status` IN ('P', 'S') AND
`offers`.`published_at` < 1341612000 AND
`offers`.`end_at` >1341567914
) AS tmp
WHERE coupons_sold < max_available
ORDER BY created_at DESC
LIMIT 4 OFFSET 0 ;

Related

MySQL query with WHERE subquery does not work on no result

I have written a complex query in MySQL to return a result.
it works perfectly
Until .....
the subquery returns no result
how to write an if or IF null then substitute in date '2020-06-03'
any help greatly appreciated
SELECT
*
FROM
trades
WHERE
stock_code = 'IHVV'
AND acc_id = '4'
AND tx_date >
(SELECT tx_date
FROM
( SELECT *, ( #sum_units := #sum_units + units ) AS sum_units
FROM
trades
JOIN ( SELECT #sum_units := 0 ) params
WHERE
stock_code = 'IHVV'
AND acc_id = '4'
AND tx_date <= '2021-06-30'
AND ( transfer_date IS NULL OR transfer_date <= '2021-06-30' )
ORDER BY
tx_date ASC,
units ASC
) AS query1
WHERE
tx_date < DATE_SUB( '2021-06-30', INTERVAL 1 YEAR )
AND sum_units = 0
ORDER BY
tx_date DESC
LIMIT 1
)
AND tx_date <= '2021-06-30'
AND ( transfer_date IS NULL OR transfer_date <= '2021-06-30' )
ORDER BY
tx_date ASC,
units ASC
clarification
I have written a main query and in one of the where clauses I am using a subquery and this subquery works well, until this subquery does not return a result and my main query stops working, so I would like to on no result in this subquery substitute a value on no result so the main query can function normally
example needed
select * from table where date > (ifnull(subquery, "2002-01-01"))
I get
incorrect parameter count in the call to native function "IFNULL'
AND THE ANSWER IS: ---> :)
thanks guys for all your suggestions
much appreciated
SELECT *
FROM trades
WHERE stock_code = 'IHVV'
AND acc_id = '4'
AND tx_date >
#last 0 date out of 1 year perhaps change the date range by from date and to date in the interval 1 year area
(SELECT COALESCE(
(SELECT tx_date
FROM (SELECT *, (#sum_units := #sum_units + units) AS sum_units
FROM trades
JOIN ( SELECT #sum_units := 0 ) params
WHERE stock_code = 'ANZ'
AND acc_id = '4'
AND tx_date <= '2022-06-30'
AND (transfer_date IS NULL OR transfer_date <= '2022-06-30' ))
ORDER BY tx_date ASC, units ASC) as query1
WHERE tx_date < DATE_SUB('2022-06-30',INTERVAL 1 YEAR)
AND sum_units = 0
ORDER BY tx_date DESC
LIMIT 1), 'TODATE')
AND tx_date <= '2022-06-30'
AND (transfer_date IS NULL OR transfer_date <= '2022-06-30' )
ORDER BY tx_date ASC, units ASC

MySQL duration for 9 rows, that's my code

SELECT DATE_FORMAT(b.checktime,"%Y-%m-%d") AS dtDate,
case when (
SELECT DATE_FORMAT(a.checktime,'%H:%i:%s')
FROM checkinout a
WHERE a.checktype='0'
and a.userid=1
and DATE_FORMAT(a.checktime,'%Y-%m-%d')=DATE_FORMAT(b.checktime,'%Y-%m-%d')
LIMIT 1)
is not NULL
then
(
SELECT
DATE_FORMAT(a.checktime,'%H:%i:%s')
FROM checkinout a
WHERE a.checktype='0'
and a.userid=1
and DATE_FORMAT(a.checktime,'%Y-%m-%d')=DATE_FORMAT(b.checktime,'%Y-%m-%d')
LIMIT 1
)
else 'N/A' END
AS Chkin
from checkinout b
where
DATE_FORMAT(b.checktime,"%m")='06' AND
DATE_FORMAT(b.checktime,"%Y")='2019' AND
DATE_FORMAT(b.checktime,"%w")!='0' AND .
DATE_FORMAT(b.checktime,"%w")!='6' AND .
DATE_FORMAT(b.checktime,"%Y-%m-%d") not in
(select date_s from wend)
GROUP BY dtDate
ORDER BY dtDate DESC
Affected rows: 0 Found rows: 9 Warnings: 0 Duration for 1 query: 25.665 sec.
what's wrong with this query, for 9 rows need 25.665 seconds
Thanks
Without understanding the purpose of the query, it can be rewritten to:
SELECT DISTINCT date(b.checktime) AS dtDate,
coalesce((
SELECT time(a.checktime)
FROM checkinout a
WHERE a.checktype = '0'
and a.userid = 1
and date(a.checktime) = date(b.checktime)
LIMIT 1
), 'N/A') AS Chkin
from checkinout b
where month(b.checktime) = 6
AND year(b.checktime) = 2019
AND weekday(b.checktime) not in (5, 6) -- non weekend
AND date(b.checktime) not in (select date_s from wend)
ORDER BY dtDate DESC
Though GROUP BY might perform better than DISTINCT - You should test both. However, the above query can be optimized to use indexes.
The outer condition month(b.checktime) = 6 AND year(b.checktime) = 2019 can be rewritten to b.checktime >= '2019-06-01' AND b.checktime < '2019-06-01' + INTERVAL 1 MONTH. This way the engine should be able to use an index on (checktime).
The condition date(a.checktime) = date(b.checktime) can be written as a.checktime >= date(b.checktime) and a.checktime < date(b.checktime) + INTERVAL 1 DAY. Here I suggest one of the following indexes: (checktype, userid, checktime), (userid, checktype, checktime) or (userid, checktime).
And for date(b.checktime) not in (select date_s from wend) it might be better to use an "anti-join".
So here is the final query, which I would try:
SELECT DISTINCT date(b.checktime) AS dtDate,
coalesce((
SELECT time(a.checktime)
FROM checkinout a
WHERE a.checktype = '0'
and a.userid = 1
and a.checktime >= date(b.checktime)
and a.checktime < date(b.checktime) + INTERVAL 1 DAY
LIMIT 1
), 'N/A') AS Chkin
from checkinout b
LEFT JOIN wend w ON w.date_s = date(b.checktime)
where b.checktime >= '2019-06-01'
AND b.checktime < '2019-06-01' + INTERVAL 1 MONTH
AND weekday(b.checktime) not in (5, 6) -- non weekend
AND w.date_s IS NULL
ORDER BY dtDate DESC

MySQL: SELECT query, but then delete records from that query where columns equal

This is my initial query:
SELECT bid_tag.*
FROM bid_tag join
(select serial_number, count(*) as cnt
from bid_tag where user_id = 0
group by serial_number
) tsum
on tsum.serial_number = bid_tag.serial_number and cnt > 1
order by bid_tag.serial_number
LIMIT 0, 21000;
Now from those results, I need to SELECT all where tag_design = 0 AND tag_size = 0 and then DELETE those records from the database.
I just don't know how to run a query on the results of an initial query.
Just replace SELECT with DELETE and it will delete the rows that would have been selected.
DELETE bid_tag.*
FROM bid_tag join
(select serial_number, count(*) as cnt
from bid_tag where user_id = 0
group by serial_number
) tsum
on tsum.serial_number = bid_tag.serial_number and cnt > 1
WHERE tag_design = 0 AND tag_size = 0
order by bid_tag.serial_number
LIMIT 0, 21000;
use an EXISTS term in your where clause:
DELETE
FROM bid_tag btd
WHERE EXISTS (
SELECT 1
FROM (
SELECT bid_tag.*
FROM bid_tag bts
JOIN (
SELECT serial_number, count(*) as cnt
FROM bid_tag btj
WHERE btj.user_id = 0
GROUP BY btj.serial_number
) tsum
ON ( tsum.serial_number = bts.serial_number
AND tsum.cnt > 1
)
WHERE bts.tag_design = 0
AND bts.tag_size = 0
ORDER BY bts.serial_number
LIMIT 0
, 21000
) rs_base
WHERE rs_base.id = btd.id -- PK column
)
;
the subquery in the EXISTS term can be nested further to contain another query on the result set of the original one. just make sure that you always select the primary key of the table on which the deletion is to be performed.
note that you probably don't want to restrict yourself to a part of your result set in a delete operation so check whether you need the limiting to the top 21000 results - if you dont, drop the 'ORDER BY' and 'LIMIT' clauses.

Add string to mysql result

I need mySql result with some prefixes and suffixes. This is my code:
SELECT bk_id, bk_rtype, villas_db.v_name AS villa_name
FROM booking_db
INNER JOIN villas_db ON booking_db.bk_vid = villas_db.v_id
WHERE '2012-11-02'
BETWEEN bk_date1
AND bk_date2
ORDER BY bk_id DESC
LIMIT 0 , 30
The result are:
bk_id bk_rtype villa_name
30 2 T2
29 3 V1
So I need the result as:
bk_id bk_rtype villa_name booking_no
30 2 T2 B2-00030
29 3 V1 B3-00029
While B is a booking prefix separate by "-" and sprintf("%05d",bk_id);
Please suggest.
You may want to use CONCAT and LPAD functions as below:
SELECT bk_id, bk_rtype, villas_db.v_name AS villa_name,
CONCAT('B',bk_rtype,'-', LPAD(bk_id, 5, '0')) AS booking_no
FROM booking_db
INNER JOIN villas_db ON booking_db.bk_vid = villas_db.v_id
WHERE '2012-11-02'
BETWEEN bk_date1
AND bk_date2
ORDER BY bk_id DESC
LIMIT 0 , 30 ;
I found my solution:
SELECT bk_id, bk_rtype, villas_db.v_name AS villa_name, concat( 'B', bk_rtype, '-', lpad( bk_id, 5, 0 ) ) AS booking_no
FROM booking_db
INNER JOIN villas_db ON booking_db.bk_vid = villas_db.v_id
WHERE '2012-11-02'
BETWEEN bk_date1
AND bk_date2
ORDER BY bk_id DESC
LIMIT 0 , 30

SQL: query with complex subqueries

I have the following tables in my game's database:
rankedUp (image_id, user_id, created_at)
globalRank (image_id, rank )
matchups (user_id, image_id1, image_id2)
All image_ids in globalRank table are assigned a rank which is a float from 0 to 1
Assuming I have the current logged in user's "user_id" value, I'm looking for a query that will return a pair of image ids (imageid1, imageid2) such that:
imageid1 has lower rank than imageid2 but is also the next highest rank less than imageid2
matchups table doesn't have (userid,imageid1,imageid2) or (userid,imageid2,imageid1)
rankedup table doesn't have (userid,imageid1) or if it does, the createdat column is older than X hours
What I have so far for requirement 1 is this:
SELECT lowerImages.image_id AS lower_image, higherImages.image_id AS higher_image
FROM global_rank AS lowerImages, global_rank AS higherImages
WHERE lowerImages.rank < higherImages.rank
AND lowerImages.image_id = (
SELECT image_id
FROM (
SELECT image_id
FROM global_rank
WHERE rank < higherImages.rank
ORDER BY rank DESC
LIMIT 1 , 1
) AS tmp
)
but it doesnt work because I can't reference higherImages.rank in the subquery.
Does anyone know how I could satisfy all of those requirements in one query?
Thanks for your help
EDIT:
I now have this query but I don't know about the efficiency and I need to test it for correctness:
SELECT lowerImages.image_id AS lower_image,
max(higherImages.image_id) AS higher_image
FROM global_rank AS lowerImages, global_rank AS higherImages
WHERE lowerImages.rank < higherImages.rank
AND 1 NOT IN (select 1 from ranked_up where
lowerImages.image_id = ranked_up.image_id
AND ranked_up.user_id = $user_id
AND ranked_up.created_at > DATE_SUB(NOW(), INTERVAL 1 DAY))
AND 1 NOT IN (
SELECT 1 from matchups where user_id = $userId
AND lower_image_id = lowerImages.image_id
AND higher_image_id = higherImages.image_id
UNION
SELECT 1 from matchups where user_id = $user_id
AND lower_image_id = higherImages.image_id
AND higher_image_id = lowerImages.image_id
)
GROUP BY 1
the "not in" statements I'm using are all indexed so they should run fast. The efficiency problem I have is the group by and selection of the global_rank tables
This question is a revision of Pretty Complex SQL Query, which should no longer be answered.
select
(
select image_id, rank from
rankedup inner join globalRank
on rankedup.image_id = globalRank .image_id
where user_id = XXX
limit 1, 1
) as highest,
(
select image_id, rank from
rankedup inner join globalRank
on rankedup.image_id = globalRank .image_id
where user_id = XXX
limit 2, 1
) as secondhighest
I normally use SQL Server, but this i think is the translation for mysql :)
This should do the trick:
SELECT lowerImages.*, higherImages.*
FROM globalrank AS lowerImages, globalrank AS higherImages
WHERE lowerImages.rank < higherImages.rank
AND lowerImages.image_id = (
SELECT image_id
FROM (
SELECT image_id
FROM globalrank
WHERE rank < higherImages.rank
ORDER BY rank DESC
LIMIT 1,1
) AS tmp
)
AND NOT EXISTS (
SELECT * FROM matchups
WHERE user_id = $user_id
AND ((image_id1 = lowerImages.image_id AND image_id2 = higherImages.image_id)
OR (image_id2 = lowerImages.image_id AND image_id1 = higherImages.image_id))
)
AND higherImages.image_id NOT IN (
SELECT image_id FROM rankedup
WHERE created_at < DATE_ADD(NOW(), INTERVAL 1 DAY)
AND USER_ID <> $user_id
)
ORDER BY higherImages.rank
I'm assuming the PKs of matchups and rankedup include all columns in those tables. This would allow the second 2 sub-queries to utilize the PK indexes. You would probably want an ordered index on globalrank.rank to speed up the first sub-query.