How to convert tinyint back to boolean when reading from SQL? - mysql

`mysql> select * from movies;
+----------+-------+---------+
| movie_id | title | watched |
+----------+-------+---------+
| 1 | bo | 0 |
| 2 | NEW | 0 |
| 3 | NEW 2 | 0 |
+----------+-------+---------+
CREATE TABLE MOVIES (
movie_id INTEGER NOT NULL AUTO_INCREMENT,
title VARCHAR(50) NOT NULL,
watched BOOLEAN NOT NULL,
PRIMARY KEY (movie_id)
);
`
I am having to store the "watched" field as a tiny int instead of typical boolean, I am trying to find a way of converting it back to boolean when reading from table, so I dont have to loop through all responses and convert manually.
ie. {movie_id: 1, title: 'bo', watched: 0} ---> {movie_id: 1, title: 'bo', watched: false}
I have tried select cast but am unfamiliar with the syntax

MySQL saves Boolean as 0 and 1 as it handles all Boolean that way.
It is very practical, then you can add true or false from a comparison in a SUM without CASE WHEN or a FILTER
You need still to make a condition to give bak True or False, but they only text of course
SELECT
movie_id , title ,
CASE WHEN watched = 0 THEN 'False' ELSE 'True' END IF

This is similar to 'IF' in 'SELECT' statement - choose output value based on column values
Borrowing from the answer there,
SELECT movie_id, IF (watched > 0, true, false) as bwatched, ...
Note that this assumes your schema still includes "NOT NULL" for watched. Without that (or some extra code) NULL would become false.
The way "IF()" works is IF(expression , value / expression if true, v /e if false)

Related

Aggregating subquery keys to build a complex object

I have a table that describes a list of products made for a given order, in this every row on this table has to have a an id of the product and the reason why it was purchased,
I would like to build a json response that amounts to an array of locations the ordered product is for, within that, an array of unique product codes and with that an array of reasons why that unique product was ordered.
I've only been able to get the topmost part of my query defined but the join and sub-select nature of the request is actually getting me in a bit of a fiddle. Is this kind of thing actually possible in plpgsql?
Additionally I'd like to join product_order.reason on product_order_reason.id and retrieve the longform_text inside the table associated with this row but I figure the bigger thing is to get the return at all and that's where i've been left stumped.
product
id |name |cost |cost_rate|
--------|------------------------|------|---------|
WALLC |Wall Clock | 15.00|SINGLE |
MIRR |Mirror | 25.00|SINGLE |
KEY |Door Keys | 5.00|SINGLE |
KEYFOB |Key Fob | 40.00|SINGLE |
product_order
product_id|quantity|location |quote_detail_quote_id |is_primary_order|reason|
----------|--------|----------|------------------------------------|----------------|------|
MIRR | 2|floor_0 |C7D33FED-CB15-5796-DC7D-A7BCEA8923C5|true | 1|
KEYF | 3|floor_0 |C7D33FED-CB15-5796-DC7D-A7BCEA8923C5|true | 2|
WALLC | 3|floor_1 |C7D33FED-CB15-5796-DC7D-A7BCEA8923C5|true | 1|
WALLC | 3|floor_1 |C7D33FED-CB15-5796-DC7D-A7BCEA8923C5|true | 3|
product_order_reason
------------------------------------------------
id (varchar, pk) | shortform_text(varchar) | longform_text(varchar)
------------------------------------------------
id|shortform_text |longform_text |
--|-------------------------------------|-----------------------------------------------------|
1|Employee Room |Standard employee room with no window |
2|Meeting Room |Standard Meeting Room |
3|Mirror |Additional Mirror Request |
create
or replace
function get_breakdown_v1_0_0(p_quote_id character varying,
p_location character varying,
p_product_code character varying) returns json language plpgsql as $function$ declare row_count smallint := 0;
begin
raise notice 'Location: %',
p_location;
raise notice 'Product: %',
p_product_code;
-- Perform santiy check on quote_id so that the json does not include a null result.
select
count(*) into
strict row_count
from
quote_detail
where
quote_id = p_quote_id;
if row_count = 0 then raise 'Quote ID % not found',
p_quote_id
using ERRCODE = '02000';
-- SQL standard no_data
elseif row_count > 1 then raise 'Too many rows returned for ID %',
p_quote_id
using ERRCODE = 'P0003';
-- PL/pgSQL too_many_rows
end if;
-- Returns an object comprised of unique values for locations, where not null and their associated products
return (
select
jsonb_build_object ('locations',jsonb_agg( jsonb_build_object( 'area', location, 'items', items)))
from
(
select
location,
jsonb_agg(jsonb_build_object ('code', product_id, 'reasons', reason)) as items
from
product_order
where
(quote_detail_quote_id = p_quote_id)
and (location = p_location
or p_location is null)
and (product_id = p_product_code
or p_product_code is null)
group by
location) a );
end $function$ ;
Desired response;
{
"area": "floor_0",
"items": [
{
"code": "WALLC",
"reasons": [
{
"quantity": 2,
"reason_code": "Standard Employee Room"
},
{
"quantity": 2,
"reason_code": "Standard Cubicle"
}
]
},
{
"code": "MIRR",
"reasons": [
{
"quantity": 3,
"reason_code": "Meeting Room"
}
]
}
]
}]
Alright I think I have something for you. The idea is to build one of the arrays at a time and carry the necessary remaining info to the outer queries for further array building. You can add your constraints for quote_detail_quote_id , location, and product_id to the innermost query's WHERE clause.
SQLFiddle to show it in action.
This may take some studying:
SELECT json_build_object('area', t3.location, 'items', t3.code_json)
FROM
(
SELECT t2.location
, array_to_json(array_agg(jsonb_build_object('code', t2.product_id, 'reasons', t2.qty_reason_json))) AS code_json
FROM
(
SELECT t.location
, t.product_id
, array_to_json(array_agg(jsonb_build_object('quantity', t.quantity, 'reason_code', t.longform_text))) AS qty_reason_json
FROM
(
SELECT po.product_id
, po.quantity
, po.location
, po.reason
, por.longform_text
FROM product_order po
JOIN product_order_reason por ON (por.id = po.reason)
WHERE quote_detail_quote_id = 'C7D33FED'
) t
GROUP BY t.location, t.product_id
) t2
GROUP BY t2.location
) t3
;

Search Json with null field value sql

Using SQL statement to query JSON field value that return "null" (String null) instead of NULL value
Sample JSON value in field name field
{
"a" : "a",
"b" : null
}
Query statement
SELECT field->>'$.b' FROM table_a;
Results
+---------------+-----------------------+
| field->>'$.b' | ISNULL(field->>'$.b') |
+---------------+-----------------------+
| null | 0 |
+---------------+-----------------------+
Is anyone have way to handle "null" (String null)?
You can use IFNULL() function, to handle the case when null values is present.
SELECT IFNULL(field->>'$.b', 'null') FROM table_a;

StringIndexOutOfBoundsException on get function in GORM

I'm getting StringIndexOutOfBoundsException when i try to retrieve domain class object using get function in GORM.
DOMAIN CLASS
class Connect {
int id
long profileid
String username
char type
char superSub
String time
char class_
boolean isapilogin
static mapping = {
table "CONNECT"
version false
id column: "ID"
profileid column: "PROFILEID"
username column: "USERNAME"
type column: "TYPE"
superSub column: "SUPER_SUB"
time column: "TIME"
class_ column: "CLASS"
isapilogin column: "ISAPILOGIN"
}
static constraints = {
username maxSize: 40
type maxSize: 1
superSub maxSize: 1
time maxSize: 14
class_ maxSize: 1
}
}
MYSQL DATABASE TABLE
ID | int(10) unsigned
PROFILEID | bigint(20) unsigned
USERNAME | varchar(40)
TYPE | char(1)
SUPER_SUB | char(1)
TIME | varchar(14)
CLASS | char(1)
ISAPILOGIN | tinyint(1)
MYCONTROLLER
class DemoController {
def check() {
int id = 1001;
Connect data = Connect.get(id) // exception at this line
data.save()
render "check"
}
}
MYSQL TABLE DATA
ID PROFILEID |USERNAME | TYPE | SUPER_SUB | TIME |CLASS|ISAPILOGIN
1001 | 4 | ABHINAV | | P | 1461235989 | A | 0
1002 | 5 | GAVAN | S | P |1450155084 | A | 1
the exception is coming when i call get on ID 1001 and not coming on ID 1002. The reason i think is that for ID 1001 the type column has an empty value or space but for ID 1002 type has a char value 'S'.In my table i have a lots of rows with empty values so what i can do to avoid this exception?.
I think you should remove "id" field from domain class.
Make sure you indicate which attributes are nullable in constraint clause. In your case attribute superSub can be null:
superSub nullable: true, maxSize: 1
If you don't indicate nullable attribute in constraint clause, explicitly, Grails expect a value for those.

Update rows when condition is met in other row with same value in one column

I need to find all the rows that contain "ungraded" for "data" with "type" set to "status". If there is another row with the same "id" but contains "end" for "type" and "legacy" for "data" I need to set "ungraded" to "graded" for the row found.
id | type | data
31 | end | legacy
31 | status | ungraded
31 | other | something
56 | start | legacy
56 | status | ungraded
56 | foo | bar
In the case above id "31" "ungraded" would be set to "graded" as the other row with the same id has "end" as "type" but id "56" would stay "ungraded" as "type" is set to "start".
I am OK with standard MySQL stuff (e.g. joins, subqueries etc) but I have no idea how to even start on this one, sorry.
You can use the exists operator
UPDATE mytable t
SET data = 'graded'
WHERE t.type = 'status' AND
t.data = 'ungraded' AND
EXISTS (SELECT *
FROM mytable s
WHERE t.id = s.id AND
s.type = 'end' AND
s.data = 'legacy');

Postgresql merge rows with same key (hstore or json)

I have a table like this:
+--------+--------------------+
| ID | Attribute |
+--------+--------------------+
| 1 |"color" => "red" |
+--------+--------------------+
| 1 |"color" => "green" |
+--------+--------------------+
| 1 |"shape" => "square" |
+--------+--------------------+
| 2 |"color" => "blue" |
+--------+--------------------+
| 2 |"color" => "black" |
+--------+--------------------+
| 2 |"flavor" => "sweat" |
+--------+--------------------+
| 2 |"flavor" => "salty" |
+--------+--------------------+
And I want to run some postgres query that get a result table like this:
+--------+------------------------------------------------------+
| ID | Attribute |
+--------+------------------------------------------------------+
| 1 |"color" => "red, green", "shape" => "square" |
+--------+------------------------------------------------------+
| 2 |"color" => "blue, black", "flavor" => "sweat, salty" |
+--------+------------------------------------------------------+
The attribute column can either be hstore or json format. I wrote it in hstore for an example, but if we cannot achieve this in hstore, but in json, I would change the column to json.
I know that hstore does not support one key to multiple values, when I tried some merge method, it only kept one value for each key. But for json, I didn't find anything that supports multiple value merge like this neither. I think this can be done by function merging values for the same key into a string/text and add it back to the key/value pair. But I'm stuck in implementing it.
Note: if implement this in some function, ideally any key such as color, shape should not appear in the function since keys can be expanded dynamically.
Does anyone have any idea about this? Any advice or brainstorm might help. Thank you!
Just a note before anything else: in your desidered output I would use some proper json and not that kind of lookalike. So a correct output according to me would be:
+--------+----------------------------------------------------------------------+
| ID | Attribute |
+--------+----------------------------------------------------------------------+
| 1 | '{"color":["red","green"], "flavor":[], "shape":["square"]}' |
+--------+----------------------------------------------------------------------+
| 2 | '{"color":["blue","black"], "flavor":["sweat","salty"], "shape":[]}' |
+--------+----------------------------------------------------------------------+
A PL/pgSQL function which parses the json attributes and executes a dynamic query would do the job, something like that:
CREATE OR REPLACE FUNCTION merge_rows(PAR_table regclass) RETURNS TABLE (
id integer,
attributes json
) AS $$
DECLARE
ARR_attributes text[];
VAR_attribute text;
ARR_query_parts text[];
BEGIN
-- Get JSON attributes names
EXECUTE format('SELECT array_agg(name ORDER BY name) AS name FROM (SELECT DISTINCT json_object_keys(attribute) AS name FROM %s) AS s', PAR_table) INTO ARR_attributes;
-- Write json_build_object() query part
FOREACH VAR_attribute IN ARRAY ARR_attributes LOOP
ARR_query_parts := array_append(ARR_query_parts, format('%L, array_remove(array_agg(l.%s), null)', VAR_attribute, VAR_attribute));
END LOOP;
-- Return dynamic query
RETURN QUERY EXECUTE format('
SELECT t.id, json_build_object(%s) AS attributes
FROM %s AS t,
LATERAL json_to_record(t.attribute) AS l(%s)
GROUP BY t.id;',
array_to_string(ARR_query_parts, ', '), PAR_table, array_to_string(ARR_attributes, ' text, ') || ' text');
END;
$$ LANGUAGE plpgsql;
I've tested it and it seems to work, it returns a json with. Here is my test code:
CREATE TABLE mytable (
id integer NOT NULL,
attribute json NOT NULL
);
INSERT INTO mytable (id, attribute) VALUES
(1, '{"color":"red"}'),
(1, '{"color":"green"}'),
(1, '{"shape":"square"}'),
(2, '{"color":"blue"}'),
(2, '{"color" :"black"}'),
(2, '{"flavor":"sweat"}'),
(2, '{"flavor":"salty"}');
SELECT * FROM merge_rows('mytable');
Of course you can pass the id and attribute column names as parameters as well and maybe refine the function a bit, this is just to give you an idea.
EDIT : If you're on 9.4 please consider using jsonb datatype, it's much better and gives you room for improvements. You would just need to change the json_* functions to their jsonb_* equivalents.
If you just want this for display purposes, this might be enough:
select id, string_agg(key||' => '||vals, ', ')
from (
select t.id, x.key, string_agg(value, ',') vals
from t
join lateral each(t.attributes) x on true
group by id, key
) t
group by id;
If you are not on 9.4, you can't use the lateral join:
select id, string_agg(key||' => '||vals, ', ')
from (
select id, key, string_agg(val, ',') as vals
from (
select t.id, skeys(t.attributes) as key, svals(t.attributes) as val
from t
) t1
group by id, key
) t2
group by id;
This will return:
id | string_agg
---+-------------------------------------------
1 | color => red,green, shape => square
2 | color => blue,black, flavor => sweat,salty
SQLFiddle: http://sqlfiddle.com/#!15/98caa/2