If no result then another query, can be combined to one query? - sql

Phone_book
+----+---------+-----------+--------------+
| id | key | code | value |
+----+---------+-----------+--------------+
| 1 | MAX_VAL | 111 | reset |
+----+------+--------------+--------------+
| 2 | MIN_VAL | 222 | set |
+----+------+--------------+--------------+
| 3 | MIN_VAL | 0 | NA |
+----+---------+-----------+--------------+
Key and code combination is the primary key.
Requirement:
if KEY and CODE is present, return VALUE.
if KEY is present and CODE not exist return the VALUE of CODE 0.
Implementation:
Achieved this with using multiple query. Syntax used is for JPQL
1) "SELECT param FROM Phone_book param WHERE upper(key)=:paramKey AND code=:estCode";
if this returns null, while shoot another query
2) "SELECT param FROM Phone_book param WHERE upper(key)=:paramKey AND code=:O";
What I looking for :
Can I achieve this in one query, or a better way ?
Thanks in advance.

In Oracle SQL, the below will suffice your need. No need to write PLSQL for this.
SELECT key,
nvl(code,0) -- This will make sure if code is null then value is 0
FROM Phone_book
WHERE (key is not NULL AND CODE IS NOT NULL) -- This will help in fetching value when KEY and CODE is present
OR ( key is not null and code is null); -- This will help in fetching value when KEY is present and CODE is null.

MySQL Relevant because the question was tagged MySQL initially
You can give it a try:
SELECT
defaultTable.`key`,
COALESCE(queryTable.`value`,defaultTable.`value`) AS v
FROM
(
SELECT
`key`,
`value`
FROM Phone_book
WHERE UPPER(`key`) = ?
AND `code` = 0
) AS defaultTable
LEFT JOIN
(
SELECT
`key`,
`value`
FROM Phone_book
WHERE UPPER(`key`) = ?
AND `code` = ?
) AS queryTable
ON defaultTable.`key` = queryTable.`key`;
Note: Replace the question marks by your provided values.
When there doesn't exist any record for the supplied key and code values then queryTable.value will be NULL.
So COALESCE will pick the value from defaulTable if any.

select
case
when key is not null and code is not null then value
when key is not null and code is null then 0
end
from phone_book;

select value from (
select value, row_number() over (order by case when code = 0 then 2 else 1 end) rn
from phonebook pb
where upper(key) = :paramKey and (code = :estCode or code = 0))
where rn = 1
Select values having requested key and requested code or code 0. Sort them properly with function row_number and take first value.

Related

SQL WHERE condition when one does not return true, then try other

I have to query a table based on two fields such that if first field matches then don't check the second but if first field does not match then check if second field matches for a value
something like:
SELECT * FROM table
WHERE cart_id=389 OR (cart_id IS NULL AND user_id=26)
But if first condition succeeds, it must not check for second condition
Example:
Suppose the following is my table
id | cart_id | user_id
1 | 389 | 26
2 | null | 26
3 | 878 | 26
on querying for cart_id = 389 and user_id = 26, I should get back only record 1 and NOT 2
on querying for cart_id = 1 and user_id = 26, I should get back only records 2 and NOT 1 and 3
The only way I can think of, is to do this in two steps and check the result of the first step in the second:
with the_cart as (
SELECT *
FROM the_table
WHERE cart_id=389
)
select *
from the_cart
union all
select *
from the_table
where cart_id IS NULL
AND user_id=26
and not exists (select * from the_cart);
If the first query (using cart_id=389) returns something the second query from the union will not be run (or more precisely return no rows) due to the not exists() condition.
Online example
Based on your updated example data, your where clause would be:
WHERE cart_id = 389 and user_id = 26
but given how trivial that is, it’s difficult to believe that’s really what you’ve been asking all along.
===
Updated based on latest example…
WHERE (cart_id = 389 and user_id = 26)
OR (cart_id is null and user_id = 26)

filter a column based on another column in oracle query

I have table like this :
ID | key | value
1 | A1 |o1
1 | A2 |o2
1 | A3 |o3
2 | A1 |o4
2 | A2 |o5
3 | A1 |o6
3 | A3 |o7
4 | A3 |o8
I want to write a oracle query that can filter value column based on key column .
some thing like this
select ID
where
if key = A1 then value ='o1'
and key = A3 then value ='o4'
please help me to write this query.
***To clarify my question ,I need list of IDs in result that all condition(key-value) are true for them. for each IDs I should check key-values (with AND ) and if all conditions are true then this ID is acceptable .
thanks
IF means PL/SQL. In SQL, we use CASE expression instead (or DECODE, if you want). Doing so, you'd move value out of the expression and use something like this:
where id = 1
and value = case when key = 'A1' then 'o1'
when key = 'A3' then 'o4'
end
You are mixing filtering and selection. List the columns that you want to display in the SELECT list and the columns used to filter in the WHERE clause
SELECT key, value
FROM my_table
WHERE ID = 1 AND key IN ('A1', 'A2')
If there is no value column in your table, you can use the DECODE function
SELECT key, DECODE(key, 'A1', 'o1', 'A2', 'o4', key) AS value
FROM my_table
WHERE ID = 1
After the key, you must specify pairs of search and result values. The pairs can be followed by a default value. In this example, since we did not specify a result for 'A3', the result will be the key itself. If no default value was specified, NULL would be returned for missing search values.
update
It seems that I have misunderstood the question (see #mathguy's comment). You can filter the way you want by simply using the Boolean operators AND and OR
SELECT * FROM
FROM my_table
WHERE
ID = 1 AND
(
key = 'A1' AND value ='o1' OR
key = 'A3' AND value ='o4'
)
By using this pattern it is easy to add more constraints of this kind. Note that AND has precedence over OR (like * over +).

sql Order by Query to display the name in order

I am using oder by name in my sql query.
The following is the name in my table.
rama1
rama2
rama10
rama3
rama11
I am using the query to display the name order by name
the output is coming like,
rama1
rama10
rama11
rama2
rama3
But I need the output should be,
rama1
rama2
rama3
rama10
rama11
Please help me with the query to get the above output.
Thanks In advance
I suppose you have a wrong structure of your table. You should have a separate column, like ID of the numeric datatype, where you could keep your rama numeric part. In this case you would be able to make such queries without developing a bycicle.
In your case you can get numeric part from your string (see How to get the numeric part from a string using T-SQL? for ms sql) and order by it. But this is wrong way to go.
Try this
SELECT col FROM Table1
ORDER BY
CASE WHEN PatIndex('%[0-9]%',col) > 0
THEN RIGHT(col,LEN(col)- (PatIndex('%[0-9]%',col)-1)) * 1
ELSE col END
DEMO
Query:
SELECT t1.*
FROM Table1 t1
ORDER BY CAST(REPLACE(t1.col, 'rama', '') AS UNSIGNED) ASC
Result:
| COL |
----------
| rama1 |
| rama2 |
| rama3 |
| rama10 |
| rama11 |
Please try:
select *
From tbl
order by CAST(SUBSTRING(col, PATINDEX('%[0-9]%', col+'0'), 10) as int)

how to select one tuple in rows based on variable field value

I'm quite new into SQL and I'd like to make a SELECT statement to retrieve only the first row of a set base on a column value. I'll try to make it clearer with a table example.
Here is my table data :
chip_id | sample_id
-------------------
1 | 45
1 | 55
1 | 5986
2 | 453
2 | 12
3 | 4567
3 | 9
I'd like to have a SELECT statement that fetch the first line with chip_id=1,2,3
Like this :
chip_id | sample_id
-------------------
1 | 45 or 55 or whatever
2 | 12 or 453 ...
3 | 9 or ...
How can I do this?
Thanks
i'd probably:
set a variable =0
order your table by chip_id
read the table in row by row
if table[row]>variable, store the table[row] in a result array,increment variable
loop till done
return your result array
though depending on your DB,query and versions you'll probably get unpredictable/unreliable returns.
You can get one value using row_number():
select chip_id, sample_id
from (select chip_id, sample_id,
row_number() over (partition by chip_id order by rand()) as seqnum
) t
where seqnum = 1
This returns a random value. In SQL, tables are inherently unordered, so there is no concept of "first". You need an auto incrementing id or creation date or some way of defining "first" to get the "first".
If you have such a column, then replace rand() with the column.
Provided I understood your output, if you are using PostGreSQL 9, you can use this:
SELECT chip_id ,
string_agg(sample_id, ' or ')
FROM your_table
GROUP BY chip_id
You need to group your data with a GROUP BY query.
When you group, generally you want the max, the min, or some other values to represent your group. You can do sums, count, all kind of group operations.
For your example, you don't seem to want a specific group operation, so the query could be as simple as this one :
SELECT chip_id, MAX(sample_id)
FROM table
GROUP BY chip_id
This way you are retrieving the maximum sample_id for each of the chip_id.

How do I use a correlated sub query for a new column in my view?

I am trying to write a view that has 3 columns: Planet, Moon, and Largest.
The view is meant to show planets, their moons, and a Yes or No column indicating whether or not it is the largest moon for the planet.
Only one Basetable is used, and the columns I am referencing are moonPlanetOrbit (only not null if bodyType is = to 'Moon'), bodyName (name of the moon), and largest ('yes' or 'no').
Here is my attempt so far:
CREATE VIEW Moons (Planet, Moon, Largest)
select moonPlanetOrbited, bodyName, ('Yes' if bodyName = (SELECT top 1 moonMeanRadius from Body where moonPlanetOrbited = bodyName order by moonMeanRadius) as Largest)
I can provide any more information if needed.
Thanks,
Cody
SQL works best with sets of data. My advice is to get the set of largest moons using a SELECT statement and the MAX() function, and then join the result set with the whole table. Then test whether the moon is equal to the largest in order to print 'yes' or 'no'.
Here's an example using MySQL. I created a table Moons containing the columns moonPlanetOrbited, bodyName, moonMeanRadius. The following SQL selects the largest moonMeanRadius for a given moonPlanetOrbited:
SELECT moonPlantedOrbited, MAX(moonMeanRadius) as maxMoonRadius
FROM Moons
GROUP BY moonPlanetOrbitede
Now that we have a list of maxMoonRadius, join the result set with the entire table and test if the moonMeanRadius is equal to the maxMoonRadius:
SELECT m1.moonPlanetOrbited, m2.bodyName,
if(m1.moonMeanRadius = m2.maxMoonRadius, 'Yes', 'No') as Largest
FROM Moons m1
JOIN (
SELECT moonPlanetOrbited, MAX(moonMeanRadius) as maxMoonRadius
FROM Moons
GROUP BY moonPlanetOrbited
) m2
ON m1.moonPlanetOrbited = m2.moonPlanetOrbited;
The IF syntax is from MySQL 5.5:
http://dev.mysql.com/doc/refman/5.5/en/control-flow-functions.html#function_if
Tested using the following SQL :
CREATE TABLE Moons(
moonPlanetOrbited VARCHAR(255),
bodyName VARCHAR(255),
moonMeanRadius FLOAT
);
INSERT INTO Moons('a', 'b', 1.01);
INSERT INTO Moons('a', 'c', 1.02);
INSERT INTO Moons('a', 'd', 1.03);
INSERT INTO Moons('a', 'e', 1.04);
+-------------------+----------+---------+
| moonPlanetOrbited | bodyName | Largest |
+-------------------+----------+---------+
| a | b | No |
| a | c | No |
| a | d | No |
| a | e | Yes |
+-------------------+----------+---------+
4 rows in set (0.00 sec)
Here is my MS-SQL Syntax stab at it:
SELECT
B.moonPlanetOrbited
, B.bodyName
, CASE
WHEN B.bodyName =
(SELECT TOP 1
iB.bodyName
FROM
Body AS iB
WHERE
iB.moonPlanetOrbited = B.bodyName
ORDER BY
iB.moonMeanRadius DESC
)
THEN 'Yes'
ELSE 'No'
END CASE AS [Largest]
FROM
Body AS B
If the table uses IDs as a primary key it may be better to compare the IDs instead of the names.
Here is an attempt (untested) that resembles your approach as closely as possible, since your idea wasn't that far off:
Select
M.moonPlanetOrbited,
M.bodyName,
CASE
WHEN M.bodyName =
(SELECT top 1 bodyName from Body
where moonPlanetOrbited = M.moonPlanetOrbited
order by moonMeanRadius DESC)
Then 'Y'
Else 'N'
AS Largest
FROM body
You just needed a table prefix to actually do the correlating to the root table, and also to make sure that you were comparing apples to apples in your CASE statement.