MySQL Where IS NOT ALL NULL? - mysql

How can a query with ability to verify all selected records are not null?
For example with the following query,
verify all rows with field is_field_null is not NULL from returned level1?
SELECT * FROM (
SELECT tb_a.A, tb_b.is_field_null FROM tb_a, tb_b, tb_c
WHERE tb_a.a = "some" AND tb_a.b = "thing" AND tb_c.c = "else"
AND tb_a.b = tb_b.a
AND tb_c.b = tb_b.c
) AS level1
Suppose there are some rows with is_field_null in level1 are indeed NULL and the tables are
tb_a
a | b | A
------------------------------------------
"some" | "thing" | "XXX"
"some" | "thing" | "YYY"
tb_b
a | c | is_field_null
----------------------------------------------
"thing" | "else" | "I have things here"
"thing" | "else" | NULL
tb_c
b | c | mapper
----------------------------------------------
"else" | "else" | "ZZZ"
"else" | "else" | "KKK"
I have tried the following which it returns some row(s) with is_field_null is not null. E.g.
A | is_field_null
-----------------------------
"XXX" | "I have things here"
"YYY" | "I have things here"
SELECT * FROM (
SELECT tb_a.A, tb_b.is_field_null FROM tb_a, tb_b, tb_c
WHERE tb_a.a = "some" AND tb_a.b = "thing" AND tb_c.c = "else"
AND tb_a.b = tb_b.a
AND tb_c.b = tb_b.c
) AS level1
WHERE level1.is_field_null IS NOT NULL
I would expect an empty table. How can I do it?
E.g.
SELECT * FROM (
SELECT tb_a.A, tb_b.is_field_null FROM tb_a, tb_b, tb_c
WHERE tb_a.a = "some" AND tb_a.b = "thing" AND tb_c.c = "else"
AND tb_a.b = tb_b.a
AND tb_c.b = tb_b.c
) AS level1
WHERE level1.is_field_null IS NOT ALL NULL ??

If you are running MySQL 8.0, a simple method uses window functions:
SELECT *
FROM (
SELECT
tb_a.A,
tb_b.is_field_null,
MAX(tb_b.is_field_null IS NULL) has_null
FROM tb_a
INNER JOIN tb_b ON tb_a.b = tb_b.a
INNER JOIN tb_c ON tb_c.b = tb_b.c
WHERE
tb_a.a = 'some'
AND tb_a.b = 'thing'
AND tb_c.c = 'else'
) t
WHERE has_null = 0
Note that this uses standard, explicit joins rather than old-school, implicit joins - this ancient syntax should not be used in new code.
Also I would recommend single quotes instead of double quotes for literal strings (this is the MySQL syntax).

Related

getting multiple rows group by column

I have sql table of this structure,
id | type | name
1 | type1 | name1
2 | type1 | name2
3 | type2 | name3
4 | type2 | name4
I want to get all the names grouped by the type like this
"type1" : [name1,name2]
"type2" : [name3,name4]
I am using Laravel eloquent, I tried keyBy('type') but it gives only one row of each type.
How can get all the names of one type?
Seems like you're looking for the group_concat aggregate function:
SELECT type, CONCAT('[', GROUP_CONCAT(name), ']')
FROM mytable
GROUP BY type
As far as I know, there is no direct way to solve this problem.
I had the same problem, and solved it using foreach loop:
$data = DB::connection('myConn')
->table('myTable')
->get()->toArray();
$res = [];
foreach ($data as $entry) {
if (!isset($res[$entry->type])) {
$res[$entry->type] = [];
}
array_push($res[$entry->type], $entry->name);
}

Case statements for multiple fields when only certain cases exist for each field

We have an inventory feature where we generate Bills. There is an Edit Bill API call. We have implemented it as PATCH call.
A Bill with id = 1 has 2 LineItems :
| Stock Id | Qty | Rate |
| 10 | 2 | 10 |
| 11 | 3 | 20 |
Now lets say I want to change the quantity for stock Id : 10 to 5 and I want to change the rate for stock Id : 11 to 40
We have represented it as PATCH Call :
bill : {
id : 1
lineItems : [
{
stockId : 10,
qty : 5,
},
{
stockId : 11,
rate : 40
}
]
}
In the backend we run following query :
UPDATE `billlineitem`
SET `rate` = ( CASE
WHEN stockid = 11 THEN '40'
ELSE rate
END ),
`qty` = ( CASE
WHEN stockid = 10 THEN 5
ELSE qty
END ),
`updated_billitemquantity_at` = '2019-09-06 05:16:06.219'
WHERE `bill_id` = '1'
AND `stockid` IN ( 10, 11 )
Is it ok, in the above case when there is no change for an attribute then the else clause will take the value from the database for that attribute. The above update statement is run in a transaction.
Is this a correct approach? Will this do an update for every attribute for every stock Id. Is there a better approach?
We are using MySQL DB.
What you've written should work, but it will get very complex if you have to update different columns for many different stock IDs. It would probably be simpler, and maybe better performance, to do a separate query for each ID.
BEGIN TRANSACTION;
UPDATE billlineitem
SET rate = '40', `updated_billitemquantity_at` = '2019-09-06 05:16:06.219'
WHERE stockid = 10;
UPDATE billlineitem
SET qty = 5, `updated_billitemquantity_at` = '2019-09-06 05:16:06.219'
WHERE stockid = 11;
COMMIT;

Two things to do in MySQL IF()

I have a problem concerning the IF() function in MySQL.
I would like to return a string and change the value of a variable. Somwhat like:
IF(#firstRow=1, "Dear" AND #firstRow:=0, "dear")
This outputs only '0' instead of 'Dear'...
I would be very thankful for some input on ways I could solve this problem!
Louis :)
AND is a boolean operator, not a "also do this other thing" operator.
"Dear" AND 0 returns 0 because 0 is treated as false in MySQL and <anything> AND false will return false.
Also because the integer/boolean value of "Dear" is 0 as well. Using a string in a numeric context just reads initial digits in the string, if any, and ignores the rest.
It's not clear what your problem is, but I guess you want to capitalize the word "dear" if the row is the first one in the result set.
Instead of being too clever by half trying to fit the side-effect into your expression, do yourself a favor and break it out into a separate column:
mysql> SELECT IF(#firstRow=1, 'Dear', 'dear'), #firstRow:=0 AS _ignoreThis
-> FROM (SELECT #firstRow:=1) AS _init
-> CROSS JOIN
-> mytable;
+---------------------------------+-------------+
| IF(#firstRow=1, 'Dear', 'dear') | _ignoreThis |
+---------------------------------+-------------+
| Dear | 0 |
| dear | 0 |
| dear | 0 |
+---------------------------------+-------------+
But if you really want to make your code as confusing and unreadable as possible, you can do something like this:
SELECT IF(#firstRow=1, CONCAT('Dear', IF(#firstRow:=0, '', '')), 'dear')
FROM (SELECT #firstRow:=1) AS _init
CROSS JOIN
...
But remember this important metric of code quality: WTFs per minute.
Use a case expression instead of IF() as the syntax is far easier to follow e.g.
select
case when #firstRow = 1 then 'Dear' else 'dear' end AS Salutation
, #firstRow := 0
from (
select 1 n union all
select 2 n union all
select 3
) d
cross join (SELECT #firstRow:=1) var
+---+------------+----------------+
| | Salutation | #firstRow := 0 |
+---+------------+----------------+
| 1 | Dear | 0 |
| 2 | dear | 0 |
| 3 | dear | 0 |
+---+------------+----------------+
Demo

spark df.write quote all fields but not null values

I am trying to create a csv from values stored in the table:
| col1 | col2 | col3 |
| "one" | null | "one" |
| "two" | "two" | "two" |
hive > select * from table where col2 is null;
one null one
I am getting the csv using the below code:
df.repartition(1)
.write.option("header",true)
.option("delimiter", ",")
.option("quoteAll", true)
.option("nullValue", "")
.csv(S3Destination)
Csv I get:
"col1","col2","col3"
"one","","one"
"two","two","two"
Expected Csv:WITH NO DOUBLE QUOTES FOR NULL VALUE
"col1","col2","col3"
"one",,"one"
"two","two","two"
Any help is appreciated to know if the dataframe writer has options to do this.
You can go in a udf approach and apply on the column (using withColumn on the repartitioned datafrmae above) where possiblity of double quote empty string is there see below sample code
sqlContext.udf().register("convertToEmptyWithOutQuotes",(String abc) -> (abc.trim().length() > 0 ? abc : abc.replace("\"", " ")),DataTypes.StringType);
String has replace method which does the job.
val a = Array("'x'","","z")
println(a.mkString(",").replace("\"", " "))
will produce 'x',,z

Periodic "Opening tables" on MySQL Insert

I have a long-running insert that shows a status that toggles between "NULL" and "Opening tables"
| 5 | mckelvey | mushroom.jpl.nasa.gov:57050 | smap_ampcs_v5_2_0 | Query | 7105 | Opening tables | INSERT INTO ChannelValue
| 5 | mckelvey | mushroom.jpl.nasa.gov:57050 | smap_ampcs_v5_2_0 | Query | 7114 | NULL | INSERT INTO ChannelValue
It does this continually. Show open tables shows 10 opened tables, 5 in use.
Global status "Opened_tables" is 190 and does not increase. table_open_cache is 1024.
Is something wrong? Why does it constantly open tables for an insert already in progress?
The insert is below. The tables in the v4 database are MyISAM, and v5_2 are InnoDB. ComboParent is temporary and MyISAM. No errors in the server log.
INSERT INTO ChannelValue
SELECT
cv.sessionId,
cv.hostId,
cv.sessionFragment,
1 AS id,
cv.id AS channelDataId,
cp.parentId,
NULL AS uniqueId,
IF (cv.dnUnsignedValue IS NOT NULL,
CONVERT(cv.dnUnsignedValue, SIGNED),
cv.dnIntegerValue) AS dnPackedValue,
cv.dnDoubleValue,
sv.stringId,
cv.eu,
SET_FLAGS(cv.dnDoubleFlag,
cv.euFlag,
cv.dnAlarmState,
cv.euAlarmState,
cv.dnUnsignedValue) AS flags
FROM smap_ampcs_v4_0_0.ChannelValue AS cv
STRAIGHT_JOIN ComboParent AS cp
ON ((cv.sessionId = cp.sessionId) AND
(cv.hostId = cp.hostId) AND
(cv.sessionFragment = cp.sessionFragment) AND
(cv.sclkCoarse = cp.sclkCoarse) AND
(cv.sclkFine = cp.sclkFine) AND
(cv.ertCoarse = cp.ertCoarse) AND
(cv.ertFine = cp.ertFine) AND
(cv.scetCoarse = cp.scetCoarse) AND
(cv.scetFine = cp.scetFine) AND
(cv.dssId = cp.dssId) AND
(cv.vcid <=> cp.vcid) AND
(cv.isRealtime = cp.isRealtime))
LEFT JOIN StringValue AS sv
ON (
(cv.hostId = sv.hostId) AND
(cv.sessionId = sv.sessionId) AND
(cv.sessionFragment = sv.sessionFragment) AND
(0 = sv.fromSse) AND
(cv.dnStringValue = sv.stringValue)
)
WHERE (cv.packetId IS NULL)