How to avoid NULL when using Value-Name Mapping in

2019-08-30 04:20发布

问题:

I have a table like the following which is basically used to "give a name" to a value in a table (this table contains values for a bunch of other tables as well, not just for MYTABLE; I've omitted a few irrelevant fields from NAMEVALUEMAP):

NAMEVALUEMAP Table
---------------------
VALUE_  | NAME_
---------------------
0       | ZERO
1       | ONE

I didn't want to use JOINs so I thought of using Sub-Queries.

Problem is when a value does not exist in the NAMEVALUEMAP table then NULL is shown.
Instead of NULL I want to show the actual value from MYTABLE (MYTABLE has ID field as identity column and contains a few rows):

-- //Fine, prints word 'ZERO' when MYTABLE.ABC is 0
SELECT 
(SELECT NAME_ FROM NAMEVALUEMAP WHERE VALUE_ = (SELECT ABC FROM MYTABLE inner_ WHERE inner_.ID = outer_.ID))
FROM 
MYTABLE outer_

-- //Not Fine, prints NULL (because "999" is not in NAMEVALUEMAP). In this case, MYTABLE.ABC is 999
-- //Want it to print 999 if the value is not in NAMEVALUEMAP
SELECT 
(SELECT NAME_ FROM NAMEVALUEMAP WHERE VALUE_ = (SELECT ABC FROM MYTABLE inner_ WHERE inner_.ID = outer_.ID))
FROM 
MYTABLE outer_

-- //Tried COALESCE, but the error is "Invalid column name 'VALUE_'"
SELECT 
COALESCE((SELECT NAME_ FROM NAMEVALUEMAP WHERE VALUE_ = (SELECT ABC FROM MYTABLE inner_ WHERE inner_.ID = outer_.ID)), ABC)
FROM 
MYTABLE outer_

Also, is there a better way to do this sort of value-to-name mapping?

回答1:

I would recomend using a LEFT JOIN (is there any reason you are voidung it?) and ISNULL

SELECT  ISNULL(NAME_, ABC)
FROM    MYTABLE m LEFT JOIN
    NAMEVALUEMAP n ON m.ABC = n.VALUE_

Well, in that case you can try

SELECT  ISNULL((select NAME_ FROM NAMEVALUEMAP WHERE VALUE_ = m.ABC), m.ABC)
FROM    MYTABLE m


回答2:

It is a left join, unless you want soem EXISTS/UNION construct. Not tested:

SELECT
    COALESCE(N.VALUE, M.ABC)
FROM
    MYTABLE M
    LEFT JOIN
    NAMEVALUEMAP N ON M.VALUE N.ABC

If you really want to avoid JOINs...

SELECT
    ABC
FROM
    MYTABLE M
WHERE
    NOT EXISTS (SELECT * FROM NAMEVALUEMAP N WHERE M.VALUE N.ABC)
UNION ALL
SELECT
    VALUE
FROM
    NAMEVALUEMAP N
WHERE
    EXISTS (SELECT * FROM MYTABLE M WHERE M.VALUE N.ABC)

Edit:

The SELECT *, 1 or NULL in EXISTS question again

  • Try EXISTS (SELECT 1/0...)
  • Mentioned in ANSI SQL 1992 Standard too, page 191


回答3:

EDIT:

SELECT 
COALESCE(
   (SELECT NAME_ FROM NAMEVALUEMAP WHERE VALUE_ = 
      (SELECT ABC FROM MYINNERTABLE inner_ WHERE inner_.ID = outer_.ID)
   ),
   <int to string>(
      SELECT ABC FROM MYINNERTABLE inner_ WHERE inner_.ID = outer_.ID
   )
)

FROM 
MYTABLE outer_

where column function <int to string> is appropriate for sqlserver. In mysql it would be CAST(). Without conversion, the query will throw a wobbly about the mismatched datatypes.