Inserting a subquery with concatenation - sql

I have the following tables:
Table1
ID
Subtotal
Tax
1
2.5
0.5
2
1
0.7
4
1.25
0.5
Table2
ID
GrandTotal
Table3
ID
Item
Available
1
Book
Y
2
Apple
N
3
Coffee
Y
4
Pencil
Y
I want to insert values into Table2, where GrandTotal = the sum of Subtotal and Tax for each row in Table1. I only want to do inserts for when the IDs in Table1 don't exist in Table2. I have the following query:
INSERT INTO Table2
(ID, GrandTotal)
VALUES
(
(
SELECT
ID,
SubTotal + Tax AS GrandTotal
FROM Table1
WHERE ID IN (
SELECT ID
FROM Table3
WHERE Available = 'Y'
)
AND ID NOT IN (
SELECT ID FROM Table2
)
)
)
However, it's throwing the following errors:
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
There are more columns in the INSERT statement than values specified in the VALUES clause. The number of values in the VALUES clause must match the number of columns specified in the INSERT statement.
I'm thinking part of this error is because it's not liking how I'm trying to add the Subtotal and Tax columns together, or concatenating them. How can I fix my query to get around these errors?

Fixed the query:
INSERT INTO Table2
(ID, GrandTotal)
SELECT
ID,
SubTotal + Tax AS GrandTotal
FROM Table1
WHERE ID IN (
SELECT ID
FROM Table3
WHERE Available = 'Y'
)
AND ID NOT IN (
SELECT ID FROM Table2
)
SQL Server uses INSERT INTO SELECT, not INSERT INTO VALUES SELECT. Could've also replaced the IN/NOT IN clauses with EXISTS/NOT EXISTS, but there were only about 100 rows that had to be inserted, so it wasn't terrible (for now).

Related

Oracle SQL select greatest value of the result of two different select statements

I'm running select statements in a loop with a cursor to collect data from different tables;
Quick (NOT WORKING) example;
select DISTINCT(ordernr) from orders
INSERT INTO newtable (select Crs.ordernr as ordernr, value1 as value from table2 where table2.ordernr = Crs.ordernr );
INSERT INTO newtable (select Crs.ordernr as ordernr, value2 as value from table3 where tabel3.ordernr=Crs.ordernr ;
)
LOOP
END LOOP;
END;
What I could like is just one insert statement which insert just the biggest value of boths select statements.
I've tried to work with greatest function in my loop but i'm running stuck. Both datatypes are the same for value1 and value2
insert into newtable(select crs.ordernr as ordernr, greatest
(
select value1 as value from table1 where condition=1, select value2 as value from table2 where condition=1)
)
);
Is it possible with a select case or other way to return only one value based on conditions? For example the biggest value of value1 or value2?
You can use the greatest function and provide subqueries to it, but - follow the syntax, i.e. enclose each of them (select statements) into its own parenthesis.
Something like this:
SQL> select greatest ( (select max(sal) from emp where job = 'CLERK'),
2 (select max(sal) from emp where job = 'ANALYST')
3 ) greatest_salary
4 from dual;
GREATEST_SALARY
---------------
3450
SQL>
I have no idea what is this:
insert into newtable(select crs.ordernr as ordernr
-----------------------------
supposed to do; what is crs? Where's the from clause?
From Oracle 12, you can use:
INSERT INTO newtable (ordernr, value)
SELECT *
FROM (
SELECT Crs.ordernr as ordernr,
value1 as value
FROM table2
WHERE table2.ordernr = Crs.ordernr
UNION ALL
SELECT Crs.ordernr,
value2
FROM table3
WHERE table3.ordernr=Crs.ordernr
)
ORDER BY value DESC
FETCH FIRST ROW ONLY;
This will mean that if you extend the query to extract more columns and you want the highest of one column and the corresponding values of the other columns then the values will all come from that one row with the highest value.
db<>fiddle here

Select a row of the table with desired value, when a column's value which is not in the table is selected in where clause in keyword?

I have a table with one of the columns as ID. I have a set of values which I give in the where clause to compare the 'ID' column using 'in' keyword. I want to select the row if the value in that set of values has a record in the table. If not, the value that is not in the table has to be selected along with empty values other columns.
For example:
There is a table with columns ID & Animal. It has 8 records.
The table with all records
If I run the query:
SELECT ID, Animal from #Temp1 where ID in (4,8)
it will return the following result.
The table result filtered
But, if I run the query:
SELECT ID, Animal from #Temp1 where ID in (4,8,12)
it should return the following result.
The table result with desired values
Use a LEFT JOIN in concert with string_split() instead
Select ID = A.value
,Animal = coalesce(B.Animal,'ID Not Found')
From string_split('4,8,12',',') A
Left Join YourTable B on A.value=B.ID
Results
ID Animal
4 Donkey
8 Hampster
12 ID Not Found
If by chance string_split() is not available
Select ID = A.value
,Animal = coalesce(B.Animal,'ID Not Found')
From (values (4)
,(8)
,(12)
) A(value)
Left Join YourTable B on A.value=B.ID

sql - getting sum of same column from multiple tables

I have a few tables in my DB. Let's call them table1, table2, table3.
All of them have a column named value.
I need to create a query that will return a single number, where this number is the sum of all the value columns from all the tables together...
I've tried the following way:
SELECT (SELECT SUM(value) FROM table1) + (SELECT SUM(value) FROM table2) + (SELECT SUM(value) FROM table3) as total_sum
But when at least one of the inner SUM is NULL, the entire total value (total_sum here) is NULL, so that's not very trustworthy.
When there is no value in a certain inner SUM query, I need it to return 0, so it doesn't affect the rest of the SUM.
To make it more clear, let's say I have the following 2 tables:
TABLE1:
ID | NAME | VALUE
1 Name1 1000
2 Name2 2000
3 Name3 3000
TABLE2:
ID | NAME | VALUE
1 Name1 1500
2 Name2 2500
3 Name3 3500
Eventually, the query I need will return a single value - 13500, which is the total sum of all the values under the VALUE column of all the tables here.
All the other columns have no meaning for the needed query, and I even don't care much for performance in this case.
You can achieve it using Coalesce as follows
SELECT
(SELECT coalesce(SUM(value),0) FROM table1) +
(SELECT coalesce(SUM(value),0) FROM table2) +
(SELECT coalesce(SUM(value),0) FROM table3) as total_sum
Another approach is to use union all to merge all values into single table
select distinct coalesce(sum(a.value), 0) as total_sum from
(select value from table1
union all
select value from table 2
union all
select value from table 3) a;
You can use the ISNULL function to take care of the NULLs.
SELECT ISNULL((
SELECT SUM(value) FROM table1
)
, 0
) + ISNULL((
SELECT SUM(value) FROM table2
)
, 0
) + ISNULL((
SELECT SUM(value) FROM table3
)
, 0
) AS total_sum;
You could simply sum all of them:
select sum(total) as Total
from (
select sum(value) as total from Table1
union all
select sum(value) as total from Table2
union all
select sum(value) as total from Table3
) t;

Update a table in SQL Server 2008 R2 by a column in another table and also need a sum value

I am trying to update a table in SQL Server 2008 R2.
Table1:
id name value1
a 34 3
a 32 2
a - -
c 90 9
Table2:
id
a
expected table1:
id name value1
a 34 3
a 32 2
a - 5
c 90 9
I need to sum all value1 group by id that exists in table2.
My SQL query:
update table1
set value1 = cast(SUM(cast ([value1] as float)) as varchar(50))
GROUP BY id
where name = '-' and id in
(
select distinct id
from table2
)
I got error:
Incorrect syntax near the keyword 'GROUP'.
Any help would be appreciated.
UPDATE
update table1
set value1 = cast(SUM(cast ([value1] as float)) as varchar(50))
where name = '-' and id in
(
select distinct id
from table2
)
GROUP BY id
still :
Incorrect syntax near the keyword 'GROUP'.
You can't use that construct afaik. You need a subquery to calculate your values based on id, and update from that table:
UPDATE table1
SET value1 = SumTable.val
FROM (
SELECT T1.id, cast(SUM(cast (T1.[value1] as float)) as varchar(50)) as val
FROM table1 T1
WHERE T1.id in
(
select distinct T2.id
from table2 T2
)
GROUP BY T1.id
) AS SumTable
WHERE table1.id = SumTable.id
If you just want to return the grouped result, you can do this by running the following
SELECT ID, SUM(Value)
FROM Table1
WHERE ID IN (SELECT ID FROM Table2) GROUP BY ID
If, however, you want to replace the contents of table1, there's no trivial way of doing this in a single operation. You need 'cache' the intermediate result before recreating the original table:
DECLARE #TEMPTABLE TABLE (ID int, Value int);
INSERT INTO #TEMPTABLE SELECT ID, SUM(Value)
FROM Table1
WHERE ID IN (SELECT ID FROM Table2) GROUP BY ID
DROP TABLE Table1
SELECT * INTO Table1 FROM #TempTable
SELECT * FROM TABLE1
(note, that was from your first edit)
If you just want to add additional 'sum' lines to the table, then you should be able to avoid the temp table and instead issue an INSERT INTO statement using the SELECT statement I gave first as a sub-query.
I do think what you're doing is quite strange, however, and you may want to think about what you're doing with your tables.
Your casting back to a VARCHAR is also a little strange - if they're always going to be an integer, keep them as integers. If they're truly VARCHARS then SUM won't always work

How to obtain count of record differences in the same table, where there are distinct and nearly-distinct records

I've a table TABLEA with data as below
field1 field2 field3.......field16
123 10-JAN-12 0.8.......ABC
123 10-JAN-12 0.8.......ABC
.
.
.
123 10-JAN-12 0.7.......ABC
245 11-JAN-12 0.3.......CDE
245 11-JAN-12 0.3.......CDE
245 11-JAN-12 0.3.......XYZ
...
<unique rows>
When I do a
select field1, field2, ...field16
from TABLEA
I obtain M records,and when I do a
select distinct field1, field2...field16
from TABLEA
I obtain M-x records, where M is in the Millions and x is a much smaller #.
I am trying to write SQL to get the x records (eventually, just get the count).
I've tried all Set operator keywords like
select field1...field16
from TABLEA
EXCEPT
select distinct field1..field16
from TABLEA
Or using UNION ALL instead of EXCEPT. But none of them return x, instead they all return 0 rows.
You can select the rows that are not distinct by
SELECT field1, ... , field16
FROM tablea
GROUP BY field1, ... , field16
HAVING count(*) > 1
Edit: Another approach would be to use an analytical function ROW_NUMBER(), partitioning by all your field columns. The first (i.e. distinct) row for a given set of fields has ROW_NUMBER = 1, the second = 2, the third = 3 etc. So you can select the x-rows with WHERE ROW_NUMBER > 1.
CREATE TABLE tablea (
field1 NUMBER, field2 DATE, field3 NUMBER, field16 VARCHAR2(10)
);
INSERT INTO tablea VALUES (123, DATE '2012-01-10', 0.8, 'ABC');
INSERT INTO tablea VALUES (123, DATE '2012-01-10', 0.8, 'ABC');
INSERT INTO tablea VALUES (123, DATE '2012-01-10', 0.7, 'ABC');
INSERT INTO tablea VALUES (245, DATE '2012-01-11', 0.3, 'CDE');
INSERT INTO tablea VALUES (245, DATE '2012-01-11', 0.3, 'CDE');
INSERT INTO tablea VALUES (245, DATE '2012-01-11', 0.3, 'XYZ');
To select the duplicate rows x:
SELECT *
FROM (
SELECT field1, field2, field3, field16,
ROWID AS rid,
ROW_NUMBER() OVER (PARTITION BY
field1, field2, field3, field16 ORDER BY ROWID) as rn
FROM tablea
)
WHERE rn > 1;
123 10.01.2012 0.8 ABC AAAJ6mAAEAAAAExAAB 2
245 11.01.2012 0.3 CDE AAAJ6mAAEAAAAExAAE 2
you will get what you want with your own 'Except' query that you have posted above. But you must include the 'ALL' keyword in your except as 'Except Distinct' is the default. So I have just added the ALL keyword below in your query itself:
select field1...field16
from TABLEA
EXCEPT ALL
select distinct field1..field16
from TABLEA
If you want a count of the records of M-x then make the above query a subquery in the FROM clause of another query and have count in that outer query and you would get the count as shown below:
Select count(*)
From
(
select field1...field16
from TABLEA
EXCEPT ALL
select distinct field1..field16
from TABLEA
) B
Guess this is what you are looking for.
Good luck
You are not going to get a count of a row result that is not in your distinct, if your column choices are the same. Distinct is showing a 'DISTINCT' possibility of all results so doing a union all is just going to repeat it and except is never going to find anything as you are limiting out your rows. What are you trying to even do? Try to count where the distincts are happening? The answer you got from Wolfgang does that already.
declare #Table Table ( personID int identity, person varchar(8));
insert into #Table values ('Brett'),('Brett'),('Brett'),('John'),('John'),('Peter');
-- gives me all results
select person
from #Table
-- gives me distinct results (no repeats)
Select distinct person
from #Table
-- gives me nothing as nothing exists that is distinct that is not in total
select person
from #Table
except
select distinct person
from #Table
-- shows me counts of rows repeated by pivoting on one column and counting resultant rows from that. Having clause adds predicate specific logic to hunt for.
-- in this case duplicates or rows greater than one
Select person, count(*)
from #Table
group by person
having count(*) > 1
EDIT you can get a difference of the distinct from the total if that is what you mean:
with dupes as
(
Select count(*) as cnts, sum(count(*)) over() as TotalDupes
from #Table
group by person
having count(*) > 1 -- dupes are defined by rows repeating
)
, uniques as
(
Select count(*) as cnts, sum(count(*)) over() as TotalUniques
from #Table
group by person
having count(*) = 1 -- non dupes are rows of only a single resulting row
)
select distinct TotalDupes - TotalUniques as DifferenceFromRepeatsToUnqiues
from Dupes, Uniques