Insert with if condition - sql

I need to create a sql statement that does this work: let's say I have two tables A and B containing integer fields. What I have to achieve is:
if (!(C is contained into A)) insert C into B
I'm using SQLite. Thanks for help

Actually, in your specific case it may happen to be as easy as
insert into B (c_value) select c_value from A where c_value = #your_c_value_here
see INSERT statement
sorry I haven't noticed the negation in your question for the C in A condition
I have another option for you
with temp_val as (select #your_val_goes_here as val)
insert into b
select val from temp_val where not exists
(select 1 from a where c = val)
check out this fiddle

Related

Update json in postgres using multiple columns

I want to update a column of JSONB objects. So If I have this table
I want to delete value1 and value2 from the rows that have a as 1 then I thought this query would work
UPDATE
test AS d
SET
b = b - s.b_value
FROM
(VALUES
(1, 'value1'),
(1, 'value2')
)
AS s(a, b_value)
WHERE
d.a = s.a
but it gives me this result where value1 was not eliminated.
Is there a simple way to fix it? I want to make a query to delete this sort of stuff but it would be a blessing if it can be done in only one query. I got the original idea from here and here you can test the SQL query
You can subtract a text[] array of keys from a jsonb value like so:
with s (a, b_value) as (
values (1, 'value1'), (1, 'value2')
), dels as (
select a, array_agg(b_value) as b_values
from s
group by a
)
update test
set b = b - dels.b_values
from dels
where dels.a = test.a;
db<>fiddle here

An equivalent expression for MIN_BY in SQL?

In SQL we have the function MIN_BY(B,C), which returns the value of B at the minimum of C.
How would one get the same functionality, but without using the MIN_BY function?
i.e. given columns A,B,C, I want to group by A and return the value of B that corresponds to the minimum of C. I can see there must be some way to do it using OVER and PARTITION BY but am not well versed in enough to see how!
One method uses window functions:
select a, min(min_bc)
from (select t.*, min(b) over (partition by a order by c) as min_bc
from t
)
group by a;
Just to understand:
SETUP:
create table Test (a int, b int, c int);
insert into test values(1,2,3);
insert into test values(1,3,2);
insert into test values(1,4,1);
insert into test values(2,4,5);
insert into test values(2,8,4);
QUERY(min(b) for the case of multiple rows with minimum of c):
select a, min(b) from Test t
where c = (select min(c) from Test b where b.a = t.a)
group by a
RESULT:
A MIN(B)
1 4
2 8
RESULT of Gordon Linoffs query:
A MIN(MIN_BC)
1 2
2 4
Who's right, who's wrong and why
If you don't want to use subquery or window functions, I wrote an alternative here (Works best for INT types as the comparator):
https://stackoverflow.com/a/75289042/1997873

SQL - Select from column A based on values in column B

Lets say I have a table with 2 columns (a, b) with following values:
a b
--- ---
1 5
1 NULL
2 NULL
2 NULL
3 NULL
My desired output:
a
---
2
3
I want to select only those distinct values from column a for which every single occurrence of this value has NULL in column b. Therefore from my desired output, "1" won't come in because there is a "5" in column b even though there is a NULL for the 2nd occurrence of "1".
How can I do this using a TSQL query?
If I understand correctly, you can do this with group by and having:
select a
from t
group by a
having count(b) = 0;
When you use count() with a column name, it counts the number of non-NULL values. Hence, if all values are NULL, then the value will be zero.
It's fairly simple to do:
SELECT A
FROM table1
GROUP BY A
HAVING COUNT(B) = 0
Grouping by A results in all the rows where the value of A is identical to be transferred into a single row in the output. Adding the HAVING clause enables to filter those grouped rows with an aggregate function. COUNT doesn't count NULL values, so when it's 0, there are no other values in B.
Two more ways to do this:
SELECT a
FROM t
EXCEPT
SELECT a
FROM t
WHERE b IS NOT NULL ;
This would use an index on (a, b):
SELECT a
FROM t
GROUP BY a
WHERE MIN(b) IS NOT NULL ;
Try it like this:
DECLARE #tbl TABLE(a INT, b INT);
INSERT INTO #tbl VALUES(1,5),(1,NULL),(2,NULL),(2,NULL),(3,NULL);
--Your test data
SELECT * FROM #tbl;
--And this is what you want - hopefully...
SELECT DISTINCT tbl.a
FROM #tbl AS tbl
WHERE NOT EXISTS(SELECT * FROM #tbl AS x WHERE x.a=tbl.a AND b IS NOT NULL)
To turn your question on it's head, you want the values from column a where there are no non-null values for that value in column b.
select distinct a
from table1 as t1
where 0 = (select count(*)
from table1 as t2
where t1.a = t2.a
and b is not null)
Sample fiddle is here: http://sqlfiddle.com/#!6/5d1b8/1
This should do it:
SELECT DISTINCT a
FROM t
WHERE b IS NULL
AND a NOT IN (SELECT a FROM t WHERE b IS NOT NULL);

SQL Join on sequence number

I have 2 tables (A, B). They each have a different column that is basically an order or a sequence number. Table A has 'Sequence' and the values range from 0 to 5. Table B has 'Index' and the values are 16740, 16744, 16759, 16828, 16838, and 16990. Unfortunately I do not know the significance of these values. But I do believe they will always match in sequential order. I want to join these tables on these numbers where 0 = 16740, 1 = 16744, etc. Any ideas?
Thanks
You could use a case expression to convert table a's values to table b's values (or vise-versa) and join on that:
SELECT *
FROM a
JOIN b ON a.[sequence] = CASE b.[index] WHEN 16740 THEN 0
WHEN 16744 THEN 1
WHEN 16759 THEN 2
WHEN 16828 THEN 3
WHEN 16838 THEN 4
WHEN 16990 THEN 5
ELSE NULL
END;
#Mureinik has a great example. If down the road you do end up adding more numbers maybe putting this information into a new table would be a good idea.
CREATE TABLE C(
AInfo INT,
BInfo INT
)
INSERT INTO TABLE C(AInfo,BInfo) VALUES(0,16740)
INSERT INTO TABLE C(AInfo,BInfo) VALUES(1,16744)
etc
Then you can Join all the tables.
If the values are in ascending order as per your example, you can use the ROW_NUMBER() function to achieve this:
;with cte AS (SELECT *, ROW_NUMBER() OVER(ORDER BY [Index])-1 RN
FROM B)
SELECT *
FROM cte

SQL Server query to Oracle query conversion

I need to write a query in Oracle, but I'm more familiar with SQL Server.
In SQL Server, the query would look as follows: (simplified)
if exists (
select * from table where a=1
)
begin
update table set b=1 where a=1
end else
begin
insert table (a,b) values(1,1)
end
Thanks for any help :)
===============================================================================
This is the Merge option, (I think):
MERGE INTO table T
USING (
SELECT a,b
FROM table
) Q
ON T.a = Q.a
WHEN MATCHED THEN
UPDATE SET T.a = 1
WHEN NOT MATCHED THEN
INSERT table (a,b) VALUES (1,1);
Is this correct?
This should be the correct syntax for Oracle 11g. I'm not an expert on Oracle so maybe someone else could explain it better, but I believe the dual table is used when inserting new values instead or trying too merge is from another table.
MERGE INTO table1 T
USING (
SELECT 1 a, 1 b FROM dual
) Q
ON (T.a = Q.a)
WHEN MATCHED THEN
UPDATE SET b = 1
WHEN NOT MATCHED THEN
INSERT (a,b) VALUES (Q.a,Q.b);
Working example