SQL select entries from table where atribute equals parameter else select * entries - sql

It is possible in SQL (ORACLE) to select all entry from a table where an atribute equals an parameter and if not select all the others entries?
like in this example:
COD | Name
1 | Monday
2 | Thursday
3 | Saturday
parameter=3
when cod equals parameter(cod=3) return entry of cod parameter(cod=3) (including cod and name)
else
return all others entries different from parameter(cod=3) (including cod and name) (like 1 Monday and 2 Thursday)
Is it possible with SQL (oracle), or i need something like PLSQL?

I'd use a correlated query and a non-correlated query:
SELECT COD, NAME
FROM TABLE a
WHERE EXISTS (SELECT 1 FROM TABLE b WHERE b.COD = a.COD AND b.COD = 3)
OR NOT EXISTS (SELECT 1 FROM TABLE c WHERE c.COD = 3)
I'm not sure if I'm following your logic, entirely, however.
And, actually, in cases where it's all from one table it can be simplified to just:
SELECT COD, NAME
FROM TABLE a
WHERE a.COD = 3
OR NOT EXISTS (SELECT 1 FROM TABLE c WHERE c.COD = 3)

IF EXISTS(SELECT 1 FROM TABLE WHERE COD=3)
THEN
SELECT COD, NAME FROM TABLE WHERE COD=3
ELSE
SELECT COD, NAME FROM TABLE
END IF

Related

SQL: select rows from a certain table based on conditions in this and another table

I have two tables that share IDs on a postgresql .
I would like to select certain rows from table A, based on condition Y (in table A) AND based on Condition Z in a different table (B) ).
For example:
Table A Table B
ID | type ID | date
0 E 1 01.01.2022
1 F 2 01.01.2022
2 E 3 01.01.2010
3 F
IDs MUST by unique - the same ID can appear only once in each table, and if the same ID is in both tables it means that both are referring to the same object.
Using an SQL query, I would like to find all cases where:
1 - the same ID exists in both tables
2 - type is F
3 - date is after 31.12.2021
And again, only rows from table A will be returned.
So the only returned row should be:1 F
It is a bit hard t understand what problem you are actually facing, as this is very basic SQL.
Use EXISTS:
select *
from a
where type = 'F'
and exists (select null from b where b.id = a.id and dt >= date '2022-01-01');
Or IN:
select *
from a
where type = 'F'
and id in (select id from b where dt >= date '2022-01-01');
Or, as the IDs are unique in both tables, join:
select a.*
from a
join b on b.id = a.id
where a.type = 'F'
and b.dt >= date '2022-01-01';
My favorite here is the IN clause, because you want to select data from table A where conditions are met. So no join needed, just a where clause, and IN is easier to read than EXISTS.
SELECT *
FROM A
WHERE type='F'
AND id IN (
SELECT id
FROM B
WHERE DATE>='2022-01-01'; -- '2022' imo should be enough, need to check
);
I don't think joining is necessary.

How add more rows when find string in column Oracle

Would it be possible to add more rows base on Keyword string in SQL ?
table A
PID PromotionName
1 OUT_EC_D10_V500K_FamilyCare_PROCO
2 OUT_EC_D5_V50K_Lunchbox_PROCO
3 OUT_EC_D5_V50K_PROCO
table B
promotion_code itm_name quantity
Lunchbox Item name 1 1
FamilyCare Item name 2 1
FamilyCare Item name 3 1
BUY1FREE6 Item name 4 1
HiSummer Item name 5 1
FamilyCare Item name 6 1
Example:
SELECT * FROM A where pid = '1';
Output of the SQL should be -
PID PromotionName Itm_name quantity
1 OUT_EC_D10_V500K_FamilyCare_PROCO
2 FamilyCare Item name 2 1
3 FamilyCare Item name 3 1
4 FamilyCare Item name 6 1
How to find string with keyword 'FamilyCare' in PromotionName of table A base on promotion_code of table B? If it exist it will add more rows in output
Any help with the SQL?
Here is how you can achieve this:
SELECT PID,PromotionName, '' as Itm_name, NULL as quantity
FROM A
WHERE pid = '1'
UNION
SELECT PID, PROMOTION_NAME, Itm_name, quantity
FROM
(SELECT * FROM A inner join B on a.promotionName LIKE '%'||b.promotion_name||'%')
WHERE pid='1'
You have to update your pid in both the places (before and after UNION).
Notice that tables were joined using LIKE operator with % before and after the word. Hence this joins if a part of a string is present in another column.
db<>fiddle link here
An option would be starting to construct a subquery factoring along with joining tables through a.promotionName LIKE '%'||b.promotion_code||'%' condition while filtering by b.promotion_code = 'FamilyCare', then add another query to combine the result sets by UNION ALL, and then enumerate with an id column by ROW_NUMBER() analytic function such as
WITH ab AS
(
SELECT a.*, b.*
FROM a
JOIN b
ON a.promotionName LIKE '%'||b.promotion_code||'%'
WHERE b.promotion_code = 'FamilyCare'
), ab2 AS
(
SELECT promotion_code, itm_name, quantity
FROM ab
UNION ALL
SELECT DISTINCT promotionName, NULL, NULL
FROM ab
)
SELECT ROW_NUMBER() OVER (ORDER BY itm_name NULLS FIRST) AS pid,
a.*
FROM ab2 a
if there's mismatch for the topmost query, then no row will be returned. eg. that query will check for the existence for the literal you provide
Demo

SQL UPDATE on the same table with WHERE

I have the following table and I want to fill up the empty values of the name column with the same value of the name where id_lang=2.
Any idea of what the sql query should be?
id_product
id_lang
name
1
1
-
1
2
name1
2
1
-
2
2
name2
3
1
-
3
2
name3
4
1
-
4
2
name4
One general approach which should work uses a correlated subquery:
UPDATE yourTable t1
SET name = (SELECT name FROM yourTable t2
WHERE t2.id_product = t1.id_product AND t2.id_lang = 2)
WHERE
name IS NULL;
In a query, you can simply use window function:
select t.*,
coalesce(name,
max(case when id_lang = 2 then name end) over (partition by id_product)
) as imputed_name
from t;
Note: This assumes that - really means NULL. If it is a string, the above can be tweaked to use CASE.
You can easily do this in an update as well, if you want to change the data in the table. However, the best way to do that depends on the database.
You can use a subquery: UPDATE table SET name = (SELECT DISTINCT name FROM table WHERE id_lang = 2)

How can I select unique rows in a database over two columns?

I have found similar solutions online but none that I've been able to apply to my specific problem.
I'm trying to "unique-ify" data from one table to another. In my original table, data looks like the following:
USERIDP1 USERIDP2 QUALIFIER DATA
1 2 TRUE AB
1 2 CD
1 3 EF
1 3 GH
The user IDs are composed of two parts, USERIDP1 and USERIDP2 concatenated. I want to transfer all the rows that correspond to a user who has QUALIFIER=TRUE in ANY row they own, but ignore users who do not have a TRUE QUALIFIER in any of their rows.
To clarify, all of User 12's rows would be transferred, but not User 13's. The output would then look like:
USERIDP1 USERIDP2 QUALIFIER DATA
1 2 TRUE AB
1 2 CD
So basically, I need to find rows with distinct user ID components (involving two unique fields) that also possess a row with QUALIFIER=TRUE and copy all and only all of those users' rows.
Although this nested query will be very slow for large tables, this could do it.
SELECT DISTINCT X.USERIDP1, X.USERIDP2, X.QUALIFIER, X.DATA
FROM YOUR_TABLE_NAME AS X
WHERE EXISTS (SELECT 1 FROM YOUR_TABLE_NAME AS Y WHERE Y.USERIDP1 = X.USERIDP1
AND Y.USERIDP2 = X.USERIDP2 AND Y.QUALIFIER = TRUE)
It could be written as an inner join with itself too:
SELECT DISTINCT X.USERIDP1, X.USERIDP2, X.QUALIFIER, X.DATA
FROM YOUR_TABLE_NAME AS X
INNER JOIN YOUR_TABLE_NAME AS Y ON Y.USERIDP1 = X.USERIDP1
AND Y.USERIDP2 = X.USERIDP2 AND Y.QUALIFIER = TRUE
For a large table, create a new auxiliary table containing only USERIDP1 and USERIDP2 columns for rows that have QUALIFIER = TRUE and then join this table with your original table using inner join similar to the second option above. Remember to create appropriate indexes.
This should do the trick - if the id fields are stored as integers then you will need to convert / cast into Varchars
SELECT 1 as id1,2 as id2,'TRUE' as qualifier,'AB' as data into #sampled
UNION ALL SELECT 1,2,NULL,'CD'
UNION ALL SELECT 1,3,NULL,'EF'
UNION ALL SELECT 1,3,NULL,'GH'
;WITH data as
(
SELECT
id1
,id2
,qualifier
,data
,SUM(CASE WHEN qualifier = 'TRUE' THEN 1 ELSE 0 END)
OVER (PARTITION BY id1 + '' + id2) as num_qualifier
from #sampled
)
SELECT
id1
,id2
,qualifier
,data
from data
where num_qualifier > 0
Select *
from yourTable
INNER JOIN (Select UserIDP1, UserIDP2 FROM yourTable WHERE Qualifier=TRUE) B
ON yourTable.UserIDP1 = B.UserIDP1 and YourTable.UserIDP2 = B.UserIDP2
How about a subquery as a where clause?
SELECT *
FROM theTable t1
WHERE CAST(t1.useridp1 AS VARCHAR) + CAST(t1.useridp2 AS VARCHAR) IN
(SELECT CAST(t2.useridp1 AS VARCHAR) + CAST(t.useridp2 AS VARCHAR)
FROM theTable t2
WHERE t2.qualified
);
This is a solution in mysql, but I believe it should transfer to sql server pretty easily. Use a subquery to pick out groups of (id1, id2) combinations with at least one True 'qualifier' row; then join that to the original table on (id1, id2).
mysql> SELECT u1.*
FROM users u1
JOIN (SELECT id1,id2
FROM users
WHERE qualifier
GROUP BY id1, id2) u2
USING(id1, id2);
+------+------+-----------+------+
| id1 | id2 | qualifier | data |
+------+------+-----------+------+
| 1 | 2 | 1 | aa |
| 1 | 2 | 0 | bb |
+------+------+-----------+------+
2 rows in set (0.00 sec)

Select values in SQL that do not have other corresponding values except those that i search for

I have a table in my database:
Name | Element
1 2
1 3
4 2
4 3
4 5
I need to make a query that for a number of arguments will select the value of Name that has on the right side these and only these values.
E.g.:
arguments are 2 and 3, the query should return only 1 and not 4 (because 4 also has 5). For arguments 2,3,5 it should return 4.
My query looks like this:
SELECT name FROM aggregations WHERE (element=2 and name in (select name from aggregations where element=3))
What do i have to add to this query to make it not return 4?
A simple way to do it:
SELECT name
FROM aggregations
WHERE element IN (2,3)
GROUP BY name
HAVING COUNT(element) = 2
If you want to add more, you'll need to change both the IN (2,3) part and the HAVING part:
SELECT name
FROM aggregations
WHERE element IN (2,3,5)
GROUP BY name
HAVING COUNT(element) = 3
A more robust way would be to check for everything that isn't not in your set:
SELECT name
FROM aggregations
WHERE NOT EXISTS (
SELECT DISTINCT a.element
FROM aggregations a
WHERE a.element NOT IN (2,3,5)
AND a.name = aggregations.name
)
GROUP BY name
HAVING COUNT(element) = 3
It's not very efficient, though.
Create a temporary table, fill it with your values and query like this:
SELECT name
FROM (
SELECT DISTINCT name
FROM aggregations
) n
WHERE NOT EXISTS
(
SELECT 1
FROM (
SELECT element
FROM aggregations aii
WHERE aii.name = n.name
) ai
FULL OUTER JOIN
temptable tt
ON tt.element = ai.element
WHERE ai.element IS NULL OR tt.element IS NULL
)
This is more efficient than using COUNT(*), since it will stop checking a name as soon as it finds the first row that doesn't have a match (either in aggregations or in temptable)
This isn't tested, but usually I would do this with a query in my where clause for a small amount of data. Note that this is not efficient for large record counts.
SELECT ag1.Name FROM aggregations ag1
WHERE ag1.Element IN (2,3)
AND 0 = (select COUNT(ag2.Name)
FROM aggregatsions ag2
WHERE ag1.Name = ag2.Name
AND ag2.Element NOT IN (2,3)
)
GROUP BY ag1.name;
This says "Give me all of the names that have the elements I want, but have no records with elements I don't want"