How to match not null + not empty? - postgresql

I have to do some queries on a messy database. Some columns are filled with either null or an empty string. I can do a query like this:
select * from a where b is not null and b <> '';
But is there a shortcut for this case? (match every "not empty" value) Something like:
select * from a where b is filled;

Just:
where b <> ''
will do what you want as null <> '' is null and the row will not be returned

select * from a where COALESCE(b, '') <> '';

Related

How do I add a where clause <> 0 for case statement in postgresql?

I have a case statement where I am trying to add a where clause <> 0 for the case statement . However, I am not able to do as the error is saying the column name is not existed. This is the current code:
SELECT *,
CASE
when A.TestValue is null then
B.Collected
when B.Collected is null then
A.TestValue
END
as Actual_Value
FROM test_Table
where Actual_Value <> 0
CASE
when A.TestValue is null then B.Collected
when B.Collected is null then A.TestValue
END <> 0

Postgres function passing array of strings

I have the Postgres function below to return some info from my DB. I need the p_ic parameter to be able to take an array of
strings.
CREATE OR REPLACE FUNCTION eddie.getinv(
IN p_ic character varying[],
IN p_id character varying)
RETURNS TABLE(cnt bigint, actualid text, actualcompany text, part text, daysinstock double precision, condition text,
ic text, price numeric, stock text, quantity bigint, location text, comments text) AS
$
BEGIN
RETURN QUERY
WITH cte AS (
SELECT
CASE WHEN partnerslist IS NULL OR partnerslist = '' THEN
'XX99'
ELSE
partnerslist
END AS a
FROM support.members WHERE id = p_id
), ctegroup AS
(
SELECT
u.id AS actualid,
(SELECT m.company || ' (' || m.id ||')' FROM support.members m WHERE m.id = u.id) AS actualcompany,
u.itemname AS part,
DATE_PART('day', CURRENT_TIMESTAMP - u.datein::timestamp) AS daysinstock,
TRIM(u.grade)::character varying AS condition,
u.vstockno::text AS stock,
u.holl::text AS ic,
CASE WHEN u.rprice > 0 THEN
u.rprice
ELSE
NULL
END AS price,
u.quantity,
u.location,
u.comments::text
FROM public.net u
WHERE u.holl in (p_ic)
AND visibledate <= now()
AND u.id = ANY(REGEXP_SPLIT_TO_ARRAY(p_id ||','|| (SELECT a FROM cte), ','))
ORDER BY u.itemname, u.id
)
SELECT
COUNT(ctegroup.ic) OVER(PARTITION BY ctegroup.ic ORDER BY ctegroup.ic) AS cnt,
actualid,
MAX(actualcompany) AS actualcompany,
MAX(part) AS part,
MAX(daysinstock) AS daysinstock,
STRING_AGG(condition,',') AS condition,
MAX(ic) AS ic,
MAX(price) AS price,
STRING_AGG(stock,',') AS stock,
SUM(quantity) AS qty,
STRING_AGG(location,',') AS location,
STRING_AGG(comments,';') AS comments
FROM ctegroup
GROUP BY part, actualid, ic
ORDER BY actualid;
END; $
LANGUAGE 'plpgsql';
I am calling it from the pgAdminIII Query window like this:
SELECT * FROM eddie.getinv(array['536-01036','536-01033L','536-01037'], 'N40')
But it is returning this error:
ERROR: operator does not exist: text = character varying[]`
LINE 28: WHERE u.holl in (p_ic)`
How do I fix this, or am I calling it incorrectly? I will be calling it from a PHP API function similar to this:
$id = 'N40';
$ic = array('536-01036','536-01033L','536-01037');
$sql = "SELECT * FROM eddie.getinv(array['". implode("','",$ic)."'], '".$id."');";
try
{
$results = pg_query($sql);
if(pg_num_rows($results) == 0) {
$rows = [];
}
else
{
$data = pg_fetch_all($results);
foreach($data as $item)
{
$rows[$item["ic"]][] = $item;
}
}
pg_free_result($results);
}
catch (Exception $e)
{
$err = array("message"=>$e->getMessage(), "code"=> $e->getCode(), "error"=>$e->__toString().",\n".print_r($_REQUEST, true));
echo json_encode($err);
}
echo json_encode($rows);
It looks like your array is being passed to the function just fine. The problem is in your query.
IN () clauses expect a comma-separated list of values. When you put an array in there, it's interpreted as a one-element list, where the value is the whole array. In other words, u.holl in (p_ic) will check if u.holl is equal to p_ic, and the comparison fails due to the type mismatch.
If you want to test the value against the contents of the array, use u.holl = ANY(p_ic).

PostgreSQL concatenate integer and real and add units

I want to concatenate 4 columns in a PostgreSQL query and add units if columns aren't empty.
SELECT
CASE
WHEN a.length_m notnull THEN a.length_m || 'm'
WHEN a.area_ar notnull THEN a.area_ar || 'ar'
WHEN a.vol notnull THEN a.vol || 'cbm'
WHEN a.pcs notnull THEN a.pcs || 'pcs'
END as quant;
FROM actions a;
This works fine, but if I have values in two colums it only shows me the first one.
How must I change my query, so that a second WHEN gets evaluated?
Use COALESCE:
SELECT COALESCE(a.length_m ||'m', '') ||
COALESCE(a.area_ar ||'ar', '') ||
COALESCE(a.vol ||'cbm', '') ||
COALESCE(a.pcs ||'pcs', '') as quant
FROM actions a;

Why do two seemingly identical where clauses involving nulls produce different results

I'm trying to select all records that don't have a null in a particular column and it's value isn't in another table.
So this particular situation I want to get all 'Instructors' from an import table that aren't already in the Individuals table. Obviously I don't want any blank instructors. My first attempt I tried using in the where clause:
(Instructor IS NOT NULL OR Instructor <> '')
However the results still included all blank records. When I tried using
ISNULL(Instructor, '') <> ''
I got the desired result. I can't see how these two where clauses could possibly produce different results. To me it seems like ISNULL converting the value to empty string for comparison should have exactly the same outcome as comparing the column to null then to empty string. What am I missing here? I'm guessing it's to do with the oddness of null values.
Below are the full queries
SELECT * FROM [tempimporttblTrainingLog]
LEFT JOIN tblIndividual I ON [Instructor] = I.FirstName + ' ' + I.Surname
WHERE (I.FirstName + ' ' + I.Surname IS NULL) AND (Instructor IS NOT NULL OR Instructor <> '')
SELECT * FROM [tempimporttblTrainingLog]
LEFT JOIN tblIndividual I ON [Instructor] = I.FirstName + ' ' + I.Surname
WHERE (I.FirstName + ' ' + I.Surname IS NULL) AND (ISNULL(Instructor, '') <> '')
ISNULL(Instructor, '') <> '' (1)
is equivalent to
(Instructor IS NOT NULL AND Instructor <> '') (2)
not
(Instructor IS NOT NULL OR Instructor <> '') (3)
If Instructor IS NULL, (1) and (2) will return FALSE, when (3) returns TRUE.
Same for when Instructor = ''.
ISNULL(Instructor, '') <> ''
won't return blank records, and you have an OR in the
(Instructor IS NOT NULL OR Instructor <> '')
line, meaning it will return anything which isn't null as well as non blanks, did you mean to put an AND instead?

Update using case and select from different table

I'm trying to do an SQL update where I want to set the value of the column being updated depending on the value in a second table. The script below shows what I'm trying to do but so far I haven't hit on the correct syntax.
update sometable set name =
case
when (select newid from lookuptable where oldid = name) <> null then newid
else name
end
UPDATE T
SET
T.name = L.newid
FROM sometable T
INNER JOIN lookuptable L
ON L.oldid = T.name
There's no need for a coalesce or an outer join, because you're only interested in updating the rows that match.
Also, when comparing a value to null, you should always use X IS NULL or X IS NOT NULL rather than X = NULL or X <> NULL, because equality (and inequality) operators always return false for null values.