Mysql return null if subquery returns null - mysql

Hy guys, sometimes my subquery return null which is ok, it should return null, but in those cases i would like my "parent select" to return null.
Is that possible?
And if yes, then how?
Heres the code:
SELECT
`company`.`companyID`,
`company`.`companyName`,
`company`.`companyName`,
`company`.`companyEmail`,
`company`.`contactEmail`,
`company`.`companyTel`,
(
SELECT
`package_map`.`szekhely_endDate`
FROM
`package_map`
WHERE
`package_map`.`companyID` = `company`.`companyID`
AND
`package_map`.`active` = 1
AND
`package_map`.`szekhely_endDate` > NOW()
ORDER BY
`package_map`.`szekhely_endDate` DESC
LIMIT 1
) as endDate,
CASE
WHEN endDate = NULL
FROM
`company`
WHERE
`company`.`companyBase` = 'some address'
AND
`company`.`szekhely_check_out` = 0

Use an ordinary INNER JOIN between the two tables. If there's no matching rows in the package_map table, there won't be a row in the result. To get the latest endDate, use the MAX() function.
SELECT
`company`.`companyID`,
`company`.`companyName`,
`company`.`companyName`,
`company`.`companyEmail`,
`company`.`contactEmail`,
`company`.`companyTel`,
MAX(package_map.szekhely_endDate) AS endDate
FROM company
INNER JOIN package_map ON `package_map`.`companyID` = `company`.`companyID`
WHERE
`company`.`companyBase` = 'some address'
AND
`company`.`szekhely_check_out` = 0
AND
`package_map`.`active` = 1
AND
`package_map`.`szekhely_endDate` > NOW()
GROUP BY `company`.`companyID`

Related

SQL Convert a char to boolean

I have in my table one row with a char value. When the value is NULL then a false should be outputted. If the value is not NULL then a true should be outputted.
So when I try to set user_group.tUser to 0 or 1 then I'm getting this error:
Invalid column name 'false'.
Invalid column name 'true'.
SELECT COALESCE((SELECT name
FROM v_company
WHERE companyId = userView.companyId), ' ') AS company,
userView.value AS companyUser,
userView.display AS displayedUser,
CASE
WHEN user_group.tUser IS NULL THEN 0
ELSE 1
END AS userIsMemberOfGroup
FROM v_user userView
LEFT OUTER JOIN cr_user_group user_group
ON ( user_group.group = 'Administrators'
AND user_group.tUser = userView.value )
ORDER BY company ASC,
displayedUser ASC
I think this is the logic you want:
SELECT COALESCE(v.name, ' ') as company,
u.value as companyUser, u.display as displayedUser,
(EXISTS (SELECT 1
FROM cr_user_group ug
WHERE ug.group = 'Administrators' AND
ug.tUser = uv.value
)
) as userIsMemberOfGroup
FROM v_user u LEFT JOIN
v_company c
ON c.companyId = v.companyId
ORDER BY company ASC, displayedUser ASC ;
In general, MySQL is very flexible about going between booleans and numbers, with 0 for false and 1 for true.
You can use MySQL IF function to return 'false' when name IS NULL, else 'true':
SELECT IF(name IS NULL, 'false', 'true')
FROM table;
A simple CASE expression would work here:
SELECT
name,
CASE WHEN name IS NOT NULL THEN true ELSE false END AS name_out
FROM yourTable;
We could also shorten the above a bit using IF:
IF(name IS NOT NULL, true, false)
SELECT
CASE
WHEN name IS NULL THEN 'false'
ELSE 'true'
END
FROM
table1;

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();

My two queries work separately but when I nest one inside of the other it no longer works

My first query is:
SELECT
SUM(CASE WHEN (Transactions.RegFunction = '1' AND Transactions.RegYear = "2017") THEN RegAmt END) AS GroupCurrsumFee,
SUM(CASE WHEN (Transactions.RegFunction = '1' AND Transactions.RegYear = "2017") THEN Transactions.LMSCAmt END) AS IndCurrsumFee
FROM AllTransactions
My second query is:
SELECT GroupAmt
FROM GroupFees
WHERE
'2016-11-01' BETWEEN BeginDate AND EndDate
AND RegYear = "2016"
AND GROUPID = "14"
AND RegFunction = 1;
When I run that query it returns the below:
| GroupAmt |
| 5.00 |
When I nest the second query inside of the first so that it can return that data in a column alias it does not show up. I have the two queries combined and written as the below:
SELECT
SUM(CASE WHEN (Transactions.RegFunction = '1' AND Transactions.RegYear = "2017") THEN RegAmt END) AS GroupCurrsumFee,
SUM(CASE WHEN (Transactions.RegFunction = '1' AND Transactions.RegYear = "2017") THEN Transactions.LMSCAmt END) AS IndCurrsumFee,
(SELECT GroupAmt FROM GroupFees
WHERE
'2016-11-01' BETWEEN BeginDate AND EndDate
AND RegYear = "2016"
AND GROUPID = "14"
AND RegFunction = 1) AS GroupFee
FROM AllTransactions
Use a join instead. Given the possibility that query might return NULL I suggest a left join with join condition that is always true. (Yes a bit "hacky".) Note, there is no guarantee that subquery returns just one row. If it does your overall result may not be what you are expecting.
SELECT SUM(CASE
WHEN (
Transactions.RegFunction = '1'
AND Transactions.RegYear = "2017"
)
THEN RegAmt
END) AS GroupCurrsumFee
, SUM(CASE
WHEN (
Transactions.RegFunction = '1'
AND Transactions.RegYear = "2017"
)
THEN Transactions.LMSCAmt
END) AS IndCurrsumFee
, GroupFee.GroupAmt
FROM AllTransactions
LEFT JOIN (
SELECT GroupAmt
FROM GroupFees
WHERE '2016-11-01' BETWEEN BeginDate
AND EndDate
AND RegYear = '2016'
AND GROUPID = '14'
AND RegFunction = 1
) AS GroupFee on 1=1

Need to re arrange all records into same rows

I need the following code to have all three proj1, proj4 and proj5 columns to be together in one row each according to dates.
As you can see dates are similar but it is showing in different records.
MYSQL Query is as follows:
select DISTINCT dates,proj1,proj4, proj5 from
(SELECT DISTINCT tc.dates AS dates , IF( tc.project_id = 1, tc.minutes, '' ) AS 'proj1',
IF(tc.project_id = 5, tc.minutes, '') AS 'proj5', IF(tc.project_id = 4, tc.minutes, '') AS 'proj4'
FROM timecard AS tc where (tc.dates between '2013-04-01' AND '2013-04-05') ) as X
I need all three proj1 , proj4 and proj5 records to display all in same rows and then query should have only 5 rows
You can group by the dates and then use max() to show values that are not empty
select dates, max(proj1) as proj1, max(proj4) as proj4, max(proj5) as proj5
from timecard
where tc.dates between '2013-04-01' AND '2013-04-05'
group by dates
Try this sql.
select dates,
(case t1.proj1
when t1.proj1 not null then t1.proj1
when t2.proj1 not null then t2.proj1
when t3.proj1 not null then t3.proj1
end) as "proj1",
(case t1.proj2
when t1.proj2 not null then t1.proj2
when t2.proj2 not null then t2.proj2
when t3.proj2 not null then t3.proj2
end) as "proj2",
(case t1.proj3
when t1.proj3 not null then t1.proj3
when t2.proj3 not null then t2.proj3
when t3.proj3 not null then t3.proj3
end) as "proj3"
from timecard t1,timecardt2,timecardt3
where t1.dates=t2.dates
and t2.dates=t3.dates
group by t1.dates

same table count union

SELECT COUNT(*) as totalHappenings FROM `happenings` WHERE `userId` = ?
UNION
SELECT COUNT(*) as xHappenings FROM `happenings` WHERE `userId` = ? AND `destinationObjectType` = \'2\'
UNION
SELECT COUNT(*) as yHappenings FROM `happenings` WHERE `userId` = ? AND `destinationObjectType` = \'1\'
Since it's the same table, and I don't wanna pass through 3 times the userId parameter how can I solve this the best way?
SELECT
COUNT(*) AS totalHappenings,
SUM(CASE WHEN `destinationObjectType` = \'2\' THEN 1 ELSE 0 END) AS xHappenings,
SUM(CASE WHEN `destinationObjectType` = \'1\' THEN 1 ELSE 0 END) AS yHappenings
FROM `happendings`
WHERE `userId` = ?
Result:
totalHappenings xHappenings yHappenings
24 10 14
You can do this with if statements inside select clause:
SELECT
COUNT(userId) as totalHappenings,
SUM(IF(`destinationObjectType`='2',1,0) as xHappenings,
SUM(IF(`destinationObjectType`='1',1,0) as yHappenings
FROM `happenings`
WHERE `userId` = ?
This will surely return your results in 3 columns. Your original query was returning in 3 rows but I think that is not a problem.
try the shortest way:
SELECT COUNT(*) as totalHappenings, SUM(`destinationObjectType` = \'2\') AS xHappenings, SUM(`destinationObjectType` = \'1\') AS yHappenings FROM `happenings` WHERE `userId` = ?
comparision inside SUM returns true or false (1 or 0) so there is no need for IF or CASE statements