Get non zero values including null - mysql

I have a table with column having value 0, null and 1. I need record having non 0 values, including null and 1. I need to query using eloquent.
My table looks like this:
id | user_id | medical | gsg |interview_result | flight | created_at
----------------------------------------------------------------------
1 | 1 | null | null | 1 | null | anydate
2 | 2 | 0 | null | 1 | null | anydate
3 | 3 | 1 | 1 | 1 | 1 | anydate
4 | 8 | 1 | 1 | 1 | 0 | anydate
Please answer this question. I want non 0 values including null. Mysql + Eloquent. Great if you give eloquent code.
Note: gsg, medical, interview_result should be non 0 including null. Other column needn't be used.

You have to use where clause to match rows that not include 0, here is an example:
DB::table('table')
->where('gsg', '<>', 0)
->where('medical', '<>', 0)
->where('interview_result', '<>', 0)
->get();
Hope this helps

Related

sort child / parent in same table

I have a MySQL table which is as follows:
member_id | name | parent |....
1 | john | 0 |
2 | alex | 0 |
3 | nikita | 1 |
4 | sarah | 1 |
.
.
.
i want to sort with parrent.
i try this but not work:
SELECT * FROM `members` ORDER BY COALESCE(`parrent`,`member_id`),`parrent` !=0,`member_id`
all child sorted, but parent not with them.
i want this result :
member_id | name | parent |....
2 | alex | 0 |
1 | john | 0 |
3 | nikita | 1 |
4 | sarah | 1 |
.
.
.
parents first and then childs.
is there a better solution to implement this table?
I need a table that contain families
coalesce() doesn't work because the parent is 0. You can use nullif() instead:
ORDER BY COALESCE(NULLIF(parent, 0), member_id),
(parent = 0) DESC,
member_id
Notice that I use (parent = 0) DESC for the second key. I prefer the logic to express the matches we want first, with DESC to put true values before false ones.

mysql by order by case when cast()

I need to sort the ID field, but the id field is dynamic, I need to judge before sorting, if it is a pure number, then I convert it to a numeric type and then sort. But I have some problems in order by case when cast(),can somebody help me?
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for BASIS_EXP_ORG
-- ----------------------------
DROP TABLE IF EXISTS `BASIS_EXP_ORG`;
CREATE TABLE `BASIS_EXP_ORG` (
`NAME` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'name',
`ORG_ID` varchar(8) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'org',
PRIMARY KEY (`ORG_ID`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Compact;
-- ----------------------------
-- Records of BASIS_EXP_ORG
-- ----------------------------
INSERT INTO `BASIS_EXP_ORG` VALUES ('OU_2', '101');
INSERT INTO `BASIS_EXP_ORG` VALUES ('INV_2', '141');
INSERT INTO `BASIS_EXP_ORG` VALUES ('OU_1', '85');
SET FOREIGN_KEY_CHECKS = 1;
----------------------------------------------------------------
select distinct ORG_ID as id,
NAME as text
from BASIS_EXP_ORG
where 1 = 1
and ORG_ID in (101,141,85)
order by
case when ORG_ID REGEXP '(^[0-9])'
then ORG_ID +0
ELSE ORG_ID END
asc
Is this what you want?
I think you just need to place (ORG_ID + 0) at the order by phase to cast it to numeric type.
Please try this.
select distinct ORG_ID,
NAME as text
from BASIS_EXP_ORG
where 1 = 1
and ORG_ID in (101,141,85)
order by (ORG_ID + 0) DESC
If you're using MySQL version 8+ and MariaDB 10+, you can use REGEXP_REPLACE to remove strings then CAST it:
SELECT DISTINCT ORG_ID AS id,CAST(REGEXP_REPLACE(ORG_ID,'[a-zA-Z]','') AS SIGNED),
NAME AS TEXT
FROM BASIS_EXP_ORG
WHERE 1 = 1
ORDER BY CAST(REGEXP_REPLACE(ORG_ID,'[a-zA-Z]','') AS SIGNED) ASC;
Check demo here: https://www.db-fiddle.com/f/itK8PM7WjURn5Jaynurz4N/0
I added a few row data in the fiddle and remove the and ORG_ID in (101,141,85) in WHERE condition for testing purpose.
EDIT:
This query below should be able to get it working on older MySQL:
SELECT DISTINCT ORG_ID AS id,SUBSTRING(ORG_ID,
LEAST(
IF(LOCATE(1,org_id)=0,99,LOCATE(1,org_id)),
IF(LOCATE(2,org_id)=0,99,LOCATE(2,org_id)),
IF(LOCATE(3,org_id)=0,99,LOCATE(3,org_id)),
IF(LOCATE(4,org_id)=0,99,LOCATE(4,org_id)),
IF(LOCATE(5,org_id)=0,99,LOCATE(5,org_id)),
IF(LOCATE(6,org_id)=0,99,LOCATE(6,org_id)),
IF(LOCATE(7,org_id)=0,99,LOCATE(7,org_id)),
IF(LOCATE(8,org_id)=0,99,LOCATE(8,org_id)),
IF(LOCATE(9,org_id)=0,99,LOCATE(9,org_id))),99)+0 AS num,
NAME AS TEXT
FROM BASIS_EXP_ORG
WHERE 1 = 1
ORDER BY num ASC;
Demo on MySQL 5.7: https://www.db-fiddle.com/f/itK8PM7WjURn5Jaynurz4N/3
As you can see, I'm using a series of functions to remove the strings from the original data. First I use LOCATE to find numbers range from 1-9 and their location. The following query and result can help to clarify more:
SELECT *,
LOCATE(1,org_id),
LOCATE(2,org_id),
LOCATE(3,org_id),
LOCATE(4,org_id),
LOCATE(5,org_id),
LOCATE(6,org_id),
LOCATE(7,org_id),
LOCATE(8,org_id),
LOCATE(9,org_id) FROM BASIS_EXP_ORG;
+-------+----------+------------+------------+------------+------------+------------+------------+------------+------------+------------+
| NAME | ORG_ID | LOCATE | LOCATE | LOCATE | LOCATE | LOCATE | LOCATE | LOCATE | LOCATE | LOCATE |
| | | (1,org_id) | (2,org_id) | (3,org_id) | (4,org_id) | (5,org_id) | (6,org_id) | (7,org_id) | (8,org_id) | (9,org_id) |
+-------+----------+------------+------------+------------+------------+------------+------------+------------+------------+------------+
| OU_1 | 00000001 | 8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| OU_2 | 101 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| INV_2 | 141 | 1 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 |
| OU_3 | 81 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
| OU_1 | 85 | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 1 | 0 |
| INV_2 | a101 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| OU_1 | b40 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 |
| OU_1 | c0001 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| OU_2 | c101 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+-------+----------+------------+------------+------------+------------+------------+------------+------------+------------+------------+
The logic behind this is to know where is the location of the number stated in LOCATE (if any). Then if it returns 0 (meaning the number doesn't exists), give it 99 so when the LEAST happen, it won't see zeros. The main reason of using LEAST however is to get the first number found instead of the smallest number found. That being said, refer to the example above and look for the data with ORG_ID=81. (LOCATE(1,org_id) found number 1 in location 2 while (LOCATE(8,org_id) found the number 8 in location 1. If we took the smallest number to judge, then we will get number 1 instead of 81 in the SUBSTRING function (this took me a while to figure out ;P). Then we use them all in the SUBSTRING and we add +0 at the last value retrieved.
tl;dr > if we convert this into plain query, we will get basically something like this:
SELECT DISTINCT ORG_ID AS id, SUBSTRING(ORG_ID,**8**,99)+0 as num
FROM BASIS_EXP_ORG
WHERE 1 = 1
AND ORG_ID='00000001'
ORDER BY num ASC;
To obtain the **8** is where all the process happen.

Check for ranges overlapping database side with coalesce

I can't figure out how to check on database side if two ranges, that can handle null values (ex. range A: null - null range B: 3 - 10), overlaps.
In this case, those two ranges overlaps because in my code null - null it's equal to -∞ and +∞ so 3 - 10 is inside -∞ - +∞.
The problem is that i need to build a query that returns all the records from my table stock_rule that have a range that overlaps with the stock_rule record that i'm trying to create.
If the count is major than zero then i can't save the record.
I'm trying to achieve that using COALESCE function (MySQL 8.0) in this way:
COALESCE(rule.min_price, 0)<=COALESCE(:minPrice, rule.min_price,0) AND
COALESCE(rule.max_price, 0)<=COALESCE(:minPrice, rule.max_price, 0) AND
COALESCE(rule.min_price, 0)<=COALESCE(:maxPrice, rule.min_price,0) AND
COALESCE(rule.max_price, 0)<=COALESCE(:maxPrice, rule.max_price, 0) AND
COALESCE(:minPrice, 0)>=COALESCE(rule.min_price, :minPrice, 0) AND
COALESCE(:maxPrice,0)<=COALESCE(rule.min_price, :maxPrice, 0) AND
COALESCE(:minPrice,0)>=COALESCE(rule.max_price, :minPrice, 0) AND
COALESCE(:maxPrice, 0)<=COALESCE(rule.max_price, :maxPrice, 0)
I guess something like this would work...
DROP TABLE ranges;
CREATE TABLE ranges
(id seriAL PRIMARY KEY
,range_start INT NULL
,range_end INT NULL
);
INSERT INTO ranges VALUES
(1,NULL,NULL),
(2,3,10),
(3,12,NULL),
(4,NULL,20),
(5,10,11);
SELECT *
FROM ranges x
JOIN ranges y
ON y.id <> x.id
AND COALESCE(x.range_start,0) <= y.range_end
AND COALESCE(x.range_end,(SELECT MAX(range_end) FROM ranges)) >= y.range_start;
+----+-------------+-----------+----+-------------+-----------+
| id | range_start | range_end | id | range_start | range_end |
+----+-------------+-----------+----+-------------+-----------+
| 1 | NULL | NULL | 2 | 3 | 10 |
| 4 | NULL | 20 | 2 | 3 | 10 |
| 5 | 10 | 11 | 2 | 3 | 10 |
| 1 | NULL | NULL | 5 | 10 | 11 |
| 2 | 3 | 10 | 5 | 10 | 11 |
| 4 | NULL | 20 | 5 | 10 | 11 |
+----+-------------+-----------+----+-------------+-----------+
mysql>

MySQL query executes fine, but returns (false) empty result set when using != NULL?

I have the following result set, that I'm trying to drill down
+----+---------+---------------+---------------------+----------------------+---------------+-----------+------------------+------------------+
| id | auth_id | trusts_number | buy_sell_actions_id | corporate_actions_id | fx_actions_id | submitted | created_at | updated_at |
+----+---------+---------------+---------------------+----------------------+---------------+-----------+------------------+------------------+
| 2 | 6 | N100723 | 2 | NULL | NULL | 0 | 08/05/2015 11:30 | 08/05/2015 15:32 |
| 5 | 6 | N100723 | NULL | NULL | 1 | 0 | 08/05/2015 15:10 | 08/05/2015 15:10 |
| 6 | 6 | N100723 | NULL | NULL | 2 | 1 | 08/05/2015 15:12 | 08/05/2015 15:41 |
+----+---------+---------------+---------------------+----------------------+---------------+-----------+------------------+------------------+
This result set is generated with the query
SELECT * FROM actions WHERE auth_id = 6 AND trusts_number = 'N100723'
I also want to get rid of any field with fx_actions is NULL, so I change the query to
SELECT * FROM actions WHERE auth_id = 6 AND trusts_number = 'N100723' AND fx_actions_id != NULL
However this returns an empty result set. I've never used "negative" query parameters in MySQL before, so I'm not sure if they should take on a different syntax or what?
Any help would be much appreciated.
Normal comparison operators don't work well with NULL. Both Something = NULL and Something != NULL will return 'unknown', which causes the row to be omitted in the result. Use the special operators IS NULL and IS NOT NULL instead:
SELECT * FROM actions
WHERE auth_id = 6
AND trusts_number = 'N100723'
AND fx_actions_id IS NOT NULL
Wikipedia on NULL and its background
Because null isn't a value, you should use IS NOT NULL

Get distinct results from several tables

I need to implement mysql query to calculate space used by user's mailbox.
A message thread may have multiple messages (reply, follow up) by 2 parties
(sender/recipient) and is tagged with one or more tags (Inbox, Sent etc.).
The following conditions have to be met:
a) user is either recipient OR author of the message;
b) message IS TAGGED by any of the tags: 1,2,3,4;
c) distinct records only, ie if the thread, containing messages is tagged with
more than one of the 4 tags (for example 1 and 4: Inbox and Sent) the calculation
is done on one tag only
I have tried the following query but I am not able to get distinct values - the
subject/body values are duplicated:
SELECT SUM(LENGTH(subject)+LENGTH(body)) AS sum
FROM om_msg_message omm
JOIN om_msg_index omi ON omm.mid = omi.mid
JOIN om_msg_tags_index omti ON omi.thread_id = omti.thread_id AND omti.uid = user_id
WHERE (omi.recipient = user_id OR omi.author = user_id) AND omti.tag_id IN (1,2,3,4)
GROUP BY omi.mid;
Structure of the tables:
om_msg_message - fields subject and body are the ones to be calculated
+--------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------------------+------+-----+---------+----------------+
| mid | int(10) unsigned | NO | PRI | NULL | auto_increment |
| subject | varchar(255) | NO | | NULL | |
| body | longtext | NO | | NULL | |
| timestamp | int(10) unsigned | NO | | NULL | |
| reply_to_mid | int(10) unsigned | NO | | 0 | |
+--------------+------------------+------+-----+---------+----------------+
om_msg_index
+-----+-----------+-----------+--------+--------+---------+
| mid | thread_id | recipient | author | is_new | deleted |
+-----+-----------+-----------+--------+--------+---------+
| 1 | 1 | 1392 | 1211 | 0 | 0 |
| 2 | 1 | 1211 | 1392 | 1 | 0 |
+-----+-----------+-----------+--------+--------+---------+
om_msg_tags_index
+--------+------+-----------+
| tag_id | uid | thread_id |
+--------+------+-----------+
| 1 | 1211 | 1 |
| 4 | 1211 | 1 |
| 1 | 1392 | 1 |
| 4 | 1392 | 1 |
+--------+------+-----------+
Here's another solution:
SELECT SUM(LENGTH(omm.subject) + LENGTH(omm.body)) as totalLength
FROM om_msg_message omm
JOIN om_msg_index omi
ON omi.mid = omm.mid
AND (omi.recipient = user_id OR omi.author = user_id)
JOIN (SELECT DISTINCT thread_id
FROM om_msg_tags_index
WHERE uid = user_id
AND tag_id IN (1, 2, 3, 4)) omti
ON omti.thread_id = omi.thread_id
I'm assuming that:
user_id is a parameter marker/host variable, being queried for an individual user.
You want the total of all messages per user, not the total length of each message (which is what the GROUP BY clause in your version was getting you).
That mid in both om_msg_message and om_msg_index is unique.
So, your problem is the IN clause. I'm not a MYSQL guru, but in T-SQL you could change it to have a where clause on a subquery that contained an EXISTS so your join didn't pop out two rows. You need to compensate for the fact that you have two rows with different tagID's associated with each row of your primary join data.
The way I could do it cross-platform would be with four left-joins that linked tables then demanded a non-null value for 1, 2, 3, or 4. Fairly inefficient; I'm sure there's a better way to do it in MySQL, but now that you know what the problem is you might know a better solution.