SELECT * from a table but add conditional to one column? - sql

Is it possible in PostgreSQL to SELECT * from a table, but add a condition to one column in that result and overwrite it? I'll explain easier with a code example of what I'm trying to do (pseudo code)
SELECT
*,
CASE
WHEN column_name=1 THEN 'one'
WHEN column_name=2 THEN 'two'
ELSE 'other'
END AS column_name
FROM table
and this returns something like:
id | name | column_name | created_at
------------------------------------
1 | Title | one | 123456789
So basically, I want to get every column without having to type each column out, but specifically alter the value of one column in the result based on some condition.
=== UPDATE ======
A little more clarification on what I am doing.
I'm writing a plpgsql function that returns a type of, for the above example RETURNS schema.table. This is then (via Postgraphile) accessed through a GraphQL endpoint and returned to our app, that is all typed with TypeScript using codegen.
So in essence, the column name needs to be 1. the same name and 2. not an alias name, as Postgraphile/GraphQL won't know this value so will be omitted.
=== UPDATE 2 ======
Ok I have done it now, but a different way. I looked at it and realised there is a easier way for me to do this, and why I never did it in the first place I don't know. I won't mark this resolved though, as my answer doesn't answer this question.
To get around this, I simply return my resultset into a varaible and alter this before returning:
SELECT schema.table.* INTO cached_data
...
IF cached_data.column_name = 'something' THEN
cached_data.column_name = 'something-else';
END IF;
RETURN cached_data;
This works perfectly for my situation.

If you have to use *, specify the table (alias if necessary)
SELECT
t1.*,
CASE
WHEN column_name=1 THEN 'one'
WHEN column_name=2 THEN 'two'
ELSE 'other'
END AS column_name
FROM table t1
This will return all columns from table, plus the new column. If you want to replace that column from table, explicitly state all required columns.
Note: If column_name is already a column in the table, then you will get two columns in the result set with the same name using this approach (HT #Milney)

You can give a nickname to your table and use TABLE_ NICKNAME.* as follow:
SELECT t.*,
CASE id
WHEN 1 THEN 'one'
WHEN 2 THEN 'two'
ELSE 'other'
END AS column_name
FROM your_table t

Related

Struggling with a complicated query on row-based Field/Value table

Bare with me for a little bit of setup here please.
I have a table MAIN that has a Field/Value representation that looks like this:
I have another table called STORE_FLAG:
I am trying to write a parameterized query for which I will be given one FIELD_ID and one or more IDs from the STORE_FLAG table.
What I need to do is select from the MAIN table ROW_IDs where:
for the given FIELD_ID, the VALUE = 'YES' AND
for the given STORE_FLAG_IDS, ANY of those FIELD_IDs correspond to a VALUE = 'x' in the MAIN table.
Not that this would be a good idea, but I cannot pivot the whole table into a column-based table to then do a traditional where clause.
Example:
Given a Field_Id = 1 and a list of StoreIds = (30,50). I would want to return row_ids 1 and 2. This is because row_id 1 and 2 have a field_id 1 with value 'YES' AND at least one of the field_ids 3 and 5 have a value 'x'. But row_id 3 has a value of null for both field_id 3 and 5 and row_id 4 has a field_id 1 with value = 'NO'.
I was thinking something like this:
SELECT DISTINCT ROW_ID FROM MAIN
WHERE (FIELD_ID = :providedFieldId OR FIELD_ID IN (SELECT FIELD_ID FROM STORE_FLAG WHERE ID IN :providedStoreIdList))
AND (FIELD_VALUE = 'YES' OR FIELD_VALUE = 'x')
which (I think) works, but feels naïve to me..? I feel like there is some sort of super duper grouping way to do this, but I can't wrap my head around it. Any suggestions would be really appreciated.
here is a way to do this
select distinct m.row_id
from main m
where m.field_id=:providedFieldId
and m.field_value='YES'
and exists (select 1
from STORE_FLAG sf
join main m2
on sf.field_id=m2.field_id
where sf.id in ('30','50') /* you need to bind the values from :providedStoreIdList using a table function*/
and m2.field_value='x'
and m2.row_id=m.row_id
)
link on how to bind an in list
https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:110612348061
Your provided solution /query will not work as you say. Because in your last line of query [AND (FIELD_VALUE = 'YES' OR FIELD_VALUE = 'x')] conflict with your requirement . Using your query, you will get ROW_ID if any one is true either FIELD_VALUE = 'YES' OR FIELD_VALUE = 'x'. Which is wrong. You can see below query-
SELECT SUB_QUERY.ROW_ID FROM
(
select DISTINCT MAIN.ROW_ID,MAIN.FIELD_VALUE from STORE_FLAG
RIGHT OUTER JOIN MAIN ON STORE_FLAG.FIELD_ID=MAIN.FIELD_ID
WHERE ((STORE_FLAG.ID IN ('202','203') AND MAIN.FIELD_VALUE='x')
OR (MAIN.FIELD_ID ='1' AND MAIN.FIELD_VALUE='YES'))
) SUB_QUERY
GROUP BY SUB_QUERY.ROW_ID
HAVING (LISTAGG(SUB_QUERY.FIELD_VALUE, ',') WITHIN GROUP (ORDER BY SUB_QUERY.ROW_ID) IN ('YES,x','x,YES'))
I think you need to run and understand my sub query part at first.

Completing a given SQL statement so that another column is displayed in the end

I'm given the following statement:
SELECT id FROM record_database WHERE id = <up to me to complete the statement>
The record database has different fields, among which are id and name.
I'm supposed to complete this select statement so that it displays all the ids and all the corresponding names side by side, and this should be done using this one line of SQL code. A hint was given that UNION or OR can be used.
I tried variations of the following:
SELECT id FROM record_database WHERE id = '*'
UNION
SELECT name FROM record_database WHERE name = '*';
But none of these worked. I tried doing this with AND, tried using display columns, but those didn't work either.
Any help would be appreciated.
This smells a great deal like homework, so I won't offer a complete answer, but you can't just union queries that return dissimilar result sets. I'm inferring that ID is an integer while NAME is some varchar, which won't union as you've listed in your hint.
When you say "complete," are you restricted to adding things to the end? If so, its a non-starter. You can't increase the list of fields being returned merely by adding things to the "WHERE" clause. You need to add things to the actual field list to get them to be returned, so you might clarify whether you are truly restricted to appending to the query you;ve given.
If you are looking for:
id
name
id next
name next
Then use this trick:
SELECT col2
FROM (
SELECT id, col2=convert ( varchar (size of name field),id)
FROM table
WHERE ....
UNION ALL
SELECT id, name
FROM table
WHERE ....
)
ORDER BY id
This order by will bring id and name side by side and col2 will contain id in first row and name in second row.
Cheating. Make the select return 0 rows and add another one that will show 2 columns. All in one and the same line:
SELECT id FROM record_database WHERE id = NULL;SELECT id,name FROM record_database;
No more time should be wasted on silly problems like this.
If both id and name are char (or varchar), you could also do this, concatting the two columns into one:
SELECT id FROM record_database WHERE id = NULL
UNION ALL
SELECT id || '--' || name FROM record_database ;
The id || '--' || name part differs from one DBMS to another. In some, the + is the concat operator, in others there are special functions. So you may need to use:
id + '--' + name
or:
CONCAT(id, '--', name)
Try this
SELECT * FROM record_database WHERE id = '*' OR name = '*'

Replace value in result by a specific value

I need to make a query to collect some data from a database via SQL. In this data there is 1 value used as collection value. This are ID's of courses given. Sometimes a course can be given about f.e. Office. But people can do a course there for word, excel, powerpoint... But this is all given in 1 course by 1 tutor. Still for statistics I need to know if they participated the course for Word, Excel, Powerpoint ...
Is it possible to replace values in the resultset? With this i mean something like this:
if value = courseValue ==> replace value with specific courseValue (I can get the value via a subquery)
I hope this makes my problem clear and i appriciate all the help!
You can use a case statement in your select to return something other than the course id that is on the row. For example:
SELECT
field1 AS 'Name',
CASE
WHEN field2 = 'Foo'
THEN 'Bar'
WHEN field2 = 'Lorem'
THEN 'Ipsum'
ELSE 'Some Value'
END
AS 'Type',
field3 AS 'Description'
FROM table
If I understand you correctly, you will need something along the lines of this:
Create a new table with "courseID" and "replacementID" columns, fill it for the cases where there is a replacement
In your query do an outer join with this table over the courseID fields and also return the "replacementID", which can be null is there is no replacement
Use either the replacementID if it isn't null or the courseID

How to select items with all possible id-s or just a particular one using the same query?

Is there a variable in SQL that can be used to represent ALL the possible values of a field? Something like this pseudo-code
SELECT name FROM table WHERE id = *ALL_EXISTING_ID-s*
I want to return all rows in this case, but later when I do a search and need only one item I can simply replace that variable with the id I'm looking for, i.e.
SELECT name FROM table WHERE id = 1
The simplest way is to remove the WHERE clause. This will return all rows.
SELECT name FROM table
If you want some "magic" value you can use for the ID that you can use in your existing query and it will return all rows, I think you're out of luck.
Though you could use something like this:
SELECT name FROM table WHERE id = IFNULL(?, id)
If the value NULL is provided, all rows will be returned.
If you don't like NULL then try the following query, which will return all rows if the value -1 is provided:
SELECT name FROM table WHERE id = IFNULL(NULLIF(?, -1), id)
Another approach that achieves the same effect (but requires binding the id twice) is:
SELECT name FROM table WHERE (id = ? OR ? = -1)

How can I limit columns returned based on their value?

I have a table which looks like
index customer_number ABC CWD ROE BEE
1 1 0 0 0 1
and I want to return only the field names that have value 1 in this case 'BEE'
I found that by SHOW FIELDS I can get the names of the fields but how I can say show the field names where field value = 1?
I would use CASE statement here.
SELECT
index, customer_number,
CASE
WHEN abc=0 THEN 'abc'
WHEN cwd=0 THEN 'cwd'
END
FROM
table_name
You can't do this in a general way.
What you can do is write a sql statement like this:
select index, customer_number, decode (ABC, 1, "ABC", null) || decode (CWD, 1, "CWD", null) || decode (ROE, 1, "ROE", null) || decode (BEE, 1, "BEE", null) from aTable
It will display the column names for each entry where the value equals to one. It is oracle sql, so if you use a different rdbms the syntax will vary.
The beat it to death answer is to use CASE statements, one for each column. Something like:
SELECT CASE WHEN index=1 THEN "index" ELSE "no_index" END as i,
CASE WHEN customer=1 THEN "customer" ELSE "no_customer" END as c,
CASE WHEN ...
This is not something that SQL was really meant to do, and would be better done with application logic.
That said, if you really wanted to do it, you would probably need to involve a temp table and a SPROC:
Get the row and determine which fields are set.
Use that information to create a temp table with only the set fields.
Insert the data into that temp table, then select the rows from there.
It would be a huge mess of SQL to replace what would amount to only a few lines of application code. Probably not worth it.