MYSQL returning out of bounds date - mysql

I have a DB table with the following structure:
user_id (int) | status (int) | param1 (varchar) | param2 (varchar) | start (date) | external_id (int)
I am doing the following query:
The DB table has the following structure.
select
*
from
`users_stuff`
where
(
`status` >= '8'
and `start` between '2017-07-01' and '2017-07-11'
and `outside_url` is not null
and (
`param1` = '1'
and `param2` = 'A'
)
or (
`param1` = '0'
and `param2` = 'B'
)
and `user_id` = '14'
and `external_id` is not null
)
and `deleted_at` is null
however when the results are returned to me I see items with the "start" set to the 12th of July. Why is that? What is wrong here that would cause that?
Thanks!

I think the placement of the OR condition is casuing this behaviour. I have updated the query as below:
select
*
from
`users_stuff`
where
(
`status` >= '8'
and `start` between '2017-07-01' and '2017-07-11'
and `outside_url` is not null
and (
`param1` = '1'
and `param2` = 'A'
or
`param1` = '0'
and `param2` = 'B'
)
and `user_id` = '14'
and `external_id` is not null
)
and `deleted_at` is null

What is wrong here that would cause that?
Your query looks faulty at first glance and can lead to unexpected behavior, for example you do
`status` >= '8'
however status is int, not s string as you treat it. The same happens for all the other integers which for unknown reasons are quoted in your quest. So fix the syntax and remove all the quotes around integers, so i.e. said
`status` >= '8'
become
`status` >= 8
PS: As small "optimization", I'd move anddeleted_atis null at the beginning of your where clause: wheredeleted_atis null and ... as there's no point evaluating remaining conditions if deleted_at is not null.

Look to your OR stament after AND.
Enclose your OR statement between ().
For example WHERE ( AND criterium OR criterium) AND criterium.

Related

How to get votes with results with percent calculating

In my Laravel 5.7/mysql 5 app I have a table with votes results:
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`vote_item_id` INT(10) UNSIGNED NOT NULL,
`user_id` INT(10) UNSIGNED NOT NULL,
`is_correct` TINYINT(1) NOT NULL DEFAULT '0',
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
where boolean is_correct field is if answer was correct or incorrect.
I need to get data on percents of correct answers.
Creating such request
$voteItemUsersResultsCorrect = VoteItemUsersResult:: // Grouped by vote name
getByIsCorrect(true)->
getByCreatedAt($filter_voted_at_from, ' > ')->
getByCreatedAt($filter_voted_at_till, ' <= ')->
getByUserId($filterSelectedUsers)->
getByVote($filterSelectedVotes)->
getByVoteCategories($filterSelectedVoteCategories)->
getByVoteIsQuiz(true)->
getByVoteStatus('A')->
select( \DB::raw('count(vote_item_users_result.id) as count, votes.id, votes.name as vote_name') )->
orderBy('vote_name', 'asc')->
groupBy( 'votes.id' )->
groupBy( 'vote_name' )->
join(\DB::raw('vote_items'), \DB::raw('vote_items.id'), '=', \DB::raw('vote_item_users_result.vote_item_id'))->
join(\DB::raw('votes '), \DB::raw('votes.id'), '=', \DB::raw('vote_items.vote_id'))->
get();
I can get number of correct votes with sql request.
SELECT count(vote_item_users_result.id) AS count, votes.id, votes.name AS vote_name
FROM `vote_item_users_result`
INNER JOIN vote_items on vote_items.id = vote_item_users_result.vote_item_id
INNER JOIN votes on votes.id = vote_items.vote_id
WHERE `vote_item_users_result`.`is_correct` = '1' AND vote_item_users_result.created_at > '2018-08-01' AND vote_item_users_result.created_at <= '2018-09-22 23:59:59' AND `votes`.`is_quiz` = '1' AND `votes`.`status` = 'A'
GROUP BY `votes`.`id`, `vote_name`
ORDER BY `vote_name` asc
I know a way to get 2nd similar request with is_correct = '0' and on php side to combine results with percent calculating,
but I wonder if that could be done with eloquent in 1 request?
If yes, how ?
Thanks!
One correct raw MySQL would use conditional aggregation:
SELECT
v.id,
100.0 * COUNT(CASE WHEN vir.is_correct = 1 THEN 1 END) / COUNT(*) AS pct_correct,
100.0 * COUNT(CASE WHEN vir.is_correct = 0 THEN 1 END) / COUNT(*) AS pct_incorrect
FROM votes v
INNER JOIN vote_items vi
ON v.id = vi.vote_id
INNER JOIN vote_item_users_result vir
ON vi.id = vir.vote_item_id
WHERE
vir.created_at > '2018-08-01' AND vir.created_at < '2018-09-23' AND
v.is_quiz = '1' AND
v.status = 'A'
GROUP BY
v.id;
Now we can try writing Laravel code for this:
DB::table('vote')
->select('vote.id',
DB::raw('100.0 * COUNT(CASE WHEN vir.is_correct = 1 THEN 1 END) / COUNT(*) AS pct_correct'),
DB::raw('100.0 * COUNT(CASE WHEN vir.is_correct = 0 THEN 1 END) / COUNT(*) AS pct_incorrect'))
->join('vote_items', 'votes.id', '=', 'vote_items.vote_id')
->join('vote_item_users_result', 'vote_items.id', '=', 'vote_item_users_result.vote_item_id ')
->where([
['vote_item_users_result.created_at', '>', '2018-08-01'],
['vote_item_users_result.created_at', '<', '2018-09-23'],
['vote.is_quiz', '=', '1'],
['vote.status', '=', 'A']
])
->groupBy('vote.id')
->get();

mysql display results horizontally

I wrote some query and i got following query results.
createdate SITE1 SITE2 SITE3 SITE4 SITE5 SITE6 SITE7 SITE8 SITE9
10/2/2014 63 NULL NULL NULL NULL NULL NULL NULL NULL
10/2/2014 NULL NULL NULL NULL NULL NULL NULL NULL 10
10/3/2014 21 NULL NULL NULL NULL NULL NULL NULL NULL
10/3/2014 NULL NULL NULL NULL NULL NULL NULL NULL 4
Now i want to display like this.
createdate SITE1 SITE2 SITE3 SITE4 SITE5 SITE6 SITE7 SITE8 SITE9
10/2/2014 63 NULL NULL NULL NULL NULL NULL NULL 10
10/3/2014 21 NULL NULL NULL NULL NULL NULL NULL 4
Note: I already grouping SITE NAME and createdate.
Do u have any cool idea or something pls suggest me..
enter code here
select alldata.createdate, count(name),
case when name = 'SITE1' then count(1) end AS SITE1,
case when name = 'SITE2' then count(1) end AS SITE2,
case when name = 'SITE3' then count(1) end AS SITE3,
case when name = 'SITE4' then count(1) end AS SITE4,
case when name = 'SITE5' then count(1) end AS SITE5,
case when name = 'SITE6' then count(1) end AS SITE6,
case when name = 'SITE7' then count(1) end AS SITE7,
case when name = 'SITE8' then count(1) end AS SITE8,
case when name = 'SITE9' then count(1) end AS SITE9,
from
(
select total.createdate as createdate ,total.name as name from
(
select distinct dtr.* , ps.name ,DATE_FORMAT(dt.create_time,'%Y-%m-%d') as createdate from di_dtb_task_result dtr
inner join di_dtb_task_data_detail dt
on dtr.task_id = dt.task_id and dt.user_id <> 10000001
left join dtb_user_info ui
on ui.id = dt.user_id and dtr.task_id = dt.task_id
left join dtb_point_site ps
on ps.id=ui.user_point_site_id and dtr.task_id = dt.task_id
where dtr.status <> 9
-- group by dtr.status ,dtr.task_id , ui.id,ui.user_point_site_id , ps.name
order by dtr.task_id
) total
-- group by total.name , total.createdate
) alldata
group by alldata.createdate ,alldata.name
I think you may want to try max() function
select createdate, max(site1),max(site2),max(site3),max(site4),max(site5),max(site6),max(site7), max(site8),max(site9) from (..your_inner_query..) group by createdate
here you go with a sample sqlfiddle for your reference
Simplest solution:
Just add another group by sql wrapping your sql.
select alldata.createdate, sum(SITE1), sum(SITE2), sum(SITE3), sum(SITE4), sum(SITE5), sum(SITE6), sum(SITE7), sum(SITE8), sum(SITE9)
// inner select
group by alldata.createdate

MySQL IS NULL not working

Have some ( difficult ) MySQL query
SELECT
*,
(
SELECT
MIN(tbl.id)
FROM
stat tbl
WHERE
tbl.id > stat.id
and tbl.user_id=stat.user_id
) next_session_id,
(
Select
(case
when next_session_id IS NULL then '9999-12-31 23:59:59' else sub.date
end)
from
stat sub
where
sub.id=next_session_id
) next_date
FROM
stat
WHERE
user_id=15973
and date >'2014-06-01'
Problem in next, for last row next_session_id are NULL(check in MySQL Workbench) and it must return datetime '9999-12-31 23:59:59', but return NULL. Check IS NULL not work i think or incorrect. Why it's happen?
UPDATE
Example of result set
You should add OR next_session_id IS NULL to the WHERE clause of your subselect
SELECT
(CASE
WHEN next_session_id IS NULL THEN '9999-12-31 23:59:59' ELSE sub.date
END)
FROM
stat sub
WHERE
sub.id=next_session_id OR next_session_id IS NULL
because without that the where condition will not be true, if next_session is null.
Try changing this part
Select
(case
when next_session_id IS NULL then '9999-12-31 23:59:59' else sub.date
end)
from
stat sub
where
sub.id=next_session_id
to
case
when next_session_id IS NULL then '9999-12-31 23:59:59' else (
Select sub.date
from
stat sub
where
sub.id=next_session_id)
end
Because in MySQL, NULL = NULL doesn't evaluate to true.
In database NULL and '' (empty string) are different. So ensure you have NULL value instead of '' (empty string) in your table.
Check this query with your table
SELECT * FROM TABLE WHERE next_session_id=''
I think IS NULL is not working because of some reason, so you can use = '',
for example x is null you can use x = '' instead.

Mysql order by with grouping

Hello everyone today i got in to a problem..
first thing i have a two table each table i have "product_seq_id" column and i joined table using the same "product_seq_id"
in the second table there are multiple rows for "product_seq_id" i want only one with below condition
table2.date_start not be null
table2.date_start is equal to '0000-00-00' or table2.date_start <= CURDATE()
table2.date_end is equal to '0000-00-00' or table2.date_start >= CURDATE()
get highest table2.priority if 2 or more rows match on the same day
I have already did some work.. but the problem is in that it's not taking highest priority number while ordering the column with grouped
//My Query
SELECT
psp . *, pcp . *
FROM
sk_product_category_path pcp
left join
sk_product_special_price psp ON (psp.product_seq_id = pcp.product_seq_id)
where
pcp.category_seq_id = 146
AND psp.product_seq_id IS NOT NULL
AND CASE
WHEN
psp.date_start IS NOT NULL
THEN
(psp.date_start = '0000-00-00'
OR psp.date_start <= CURDATE())
AND (psp.date_end = '0000-00-00'
OR psp.date_end >= CURDATE())
ELSE 1 = 1
END
group by psp.product_seq_id
order by psp.priority desc
Result Came for above code:
# product_special_price_seq_id, product_special_price, date_start, date_end, priority, product_seq_id, product_category_path_seq_id, product_seq_id, category_seq_id
2309 123123 0000-00-00 0000-00-00 0 3196 1 3196 146
2307 12313 0000-00-00 0000-00-00 0 3197 3 3197 146
Result I wanted:
# product_special_price_seq_id, product_special_price, date_start, date_end, priority, product_seq_id, product_category_path_seq_id, product_seq_id, category_seq_id
2309 12200 0000-00-00 0000-00-00 1 3196 2 3196 146
2307 12313 0000-00-00 0000-00-00 0 3197 3 3197 146
// Table Data
CREATE TABLE IF NOT EXISTS `sk_product_category_path` (
`product_category_path_seq_id` int(11) NOT NULL AUTO_INCREMENT,
`product_seq_id` int(11) NOT NULL,
`category_seq_id` int(11) NOT NULL,
PRIMARY KEY (`product_category_path_seq_id`),
UNIQUE KEY `product_seq_id` (`product_seq_id`,`category_seq_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
INSERT INTO `sk_product_category_path` (`product_category_path_seq_id`, `product_seq_id`, `category_seq_id`) VALUES
(1, 3196, 146),
(2, 3197, 146),
(3, 3198, 146);
CREATE TABLE IF NOT EXISTS `sk_product_special_price` (
`product_special_price_seq_id` int(11) NOT NULL AUTO_INCREMENT,
`product_special_price` bigint(20) DEFAULT NULL,
`date_start` date DEFAULT NULL,
`date_end` date DEFAULT NULL,
`priority` int(11) DEFAULT NULL,
`product_seq_id` int(11) NOT NULL,
PRIMARY KEY (`product_special_price_seq_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
INSERT INTO `sk_product_special_price` (`product_special_price_seq_id`, `product_special_price`, `date_start`, `date_end`, `priority`, `product_seq_id`) VALUES
(1, 12313, '0000-00-00', '0000-00-00', 0, 3197),
(2, 12200, '2014-02-11', '2014-02-11', 1, 3197),
(3, 123123, '0000-00-00', '0000-00-00', 0, 3196);
During GROUP BY in MySQL, it picks first matching row for each group unless you are using an aggregate function. The first matching need not be always row with min(id) .
The possible query should be something like :
SELECT t.*
from table_name t
inner join (
select min(id) as id
from table_name t
group by col) as s
on s.id = t.id
Please find the below query.. let me know is this is your requirement?
SELECT *
FROM sk_product_special_price pspo
WHERE pspo.priority IN(SELECT MAX(psp.priority)
FROM sk_product_special_price psp
JOIN sk_product_category_path pcp
ON(pcp.product_seq_id=psp.product_seq_id)
WHERE psp.date_start IS NOT NULL
AND psp.date_start BETWEEN '0000-00-00' AND CURDATE()
AND (psp.date_end>=CURDATE() OR psp.date_end='0000-00-00')
AND pcp.product_seq_id=pspo.product_seq_id);
I have updated the end date "'2014-02-11" to "2014-02-12" for my code to fetch end date >=today's date.
this query will return the table2 details i.e table sk_product_special_price for each all the product based on the priyority values.
the output will be
product_special_price_seq_id, product_special_price, date_start, date_end, priority, product_seq_id
2, 12200, '2014-02-11', '2014-02-12', 1, 3197
3, 123123, '0000-00-00', '0000-00-00', 0, 3196

SQL - how to select values which aren't 0, but may be NULL?

In my MySQL table, I have some rows with status = NULL and some with status = 0
When selecting them in a query:
SELECT *
FROM `table`
WHERE `status` != 0
This ignores both 0 and NULL values.
How can I ignore ONLY 0 values?
You can use the is null predicate:
if status is a numeric field:
SELECT *
FROM `table`
WHERE `status` != 0
OR `status` IS NULL
if status is a text field:
SELECT *
FROM `table`
WHERE `status` != '0'
OR `status` IS NULL
This works because NULL != 0 evaluates as NULL and NULL OR TRUE evaluates as TRUE. Rows whose inclusion condition evaluates to NULL are rejected.
Didn't try it, but maybe this?
SELECT *
FROM `table`
WHERE `status` IS NULL OR `status` != 0
Judging by your sqlfiddle, it appears status is a text type, so this is what you want:
SELECT *
FROM mytable
WHERE status IS NULL
OR status != '0'
If you want to exclude them both:
SELECT *
FROM mytable
WHERE COALESCE(status,0) <> 0
;
You could use the null-safe equals operator...
SELECT status
FROM mytable
WHERE not (status <=> 0);
It considers null as just another value. 0 <=> null is false, as opposed to the null you get with normal comparisons.
As with the other answers here, quote the 0 if your status column happens to be a (var)char type.