In VBA Excel through ADO SQL, How may I refer to a record "only once" and link it to another avoiding the same record to be recalled? - sql

I have a table with 3 fields:
(the quantity are positive and negative)
TAB_A
ID | quantity | Related_ID
1 100 *? (It is 2 and it is correct)
2 -100 (nothing)
3 100 *? (It is 2 but it should be 4)
4 -100 (nothing)
and the following SQL query:
UPDATE Table_A AS ta LEFT JOIN Table_A AS tb ON ta.[quantity] = -tb.[quantity]
SET ta.Related_ID = tb.[ID]
WHERE ta.[quantity] > 0 AND tb.[Quantity] < 0
I would like to add to the query a part that recognizes the ID already used and won't use them a second time.

Something like this might help, depending on whether all your data is like the sample you posted.
query from question
and tb.id =
(select min(id)
from table_a
where id > ta.id)
The syntax might not be 100% correct but the logic should be ok. Test this by changing your update query to a select query and look at the results.

This solution is in line with my question but I do not think if it is able to cover all the cases. The initial results can be also listed as follow:
-100
-90
-100
100
90
100
The quantity could be listed in any order randomly.

Related

Filtering a column based on having some value in one of the rows in SQL or Presto Athena

I am trying in Athena to output only users which have some specific value in them but not in all of the rows
Suppose I have the table below.
I want all users which have value '100' in at least one of their rows but also having in other rows value different than 100.
user | value
A | 1
B | 2
A | 100
D | 3
A | 4
C | 3
C | 5
D | 100
So in this example I would want to get only users A and D because only them having 100 and none 100.
I tried maybe grouping by user and creating an array of values per user and then checking if array contains 100 but I don't manage doing it presto.
Also I thought about converting rows to columns and then checking if one of columns equals 100.
Those solutions are too complex? Anybody knows how to implement them or anyone has a better simpler solution?
The users that have at least one value of 100 can be found with this SQL:
SELECT DISTINCT user
FROM some_table
WHERE value = 100
But I assume you are after all tuples of user and value where the user has at least one value of 100, this can be accomplished by using the query above in a slightly more complex query:
WITH matching_users AS (
SELECT DISTINCT user
FROM some_table
WHERE value = 100
)
SELECT user, value
FROM matching_users
LEFT JOIN some_table USING (user)
You can use sub query as below to achieve your required output=
SELECT * FROM your_table
WHERE User IN(
SELECT DISTINCT User
FROM your_table
WHERE Value = 100
)
If you just want the users, I would go for aggregation:
select user
from t
group by user
having sum(case when value = 100 then 1 else 0 end) > 0;
If 100 is the maximum possible value, this can be simplified to:
having max(value) = 100

SQL - Update top n records for each value in column a where n = count of column b

I have one table with the following columns and sample values:
[test]
ID | Sample | Org | EmployeeNumber
1 100 6513241
2 200 3216542
3 300 5649841
4 100 9879871
5 200 6546548
6 100 1116594
My example count query based on [test] returns these sample values grouped by Org:
Org | Count of EmployeeNumber
100 3
200 2
300 1
My question is can I use this count to update test.Sample to 'x' for the top 3 records of Org 100, the top 2 records of Org 200, and the top 1 record of Org 300? It does not matter which records are updated, as long as the number of records updated for the Org = the count of EmployeeNumber.
I realize that I could just update all records in this example but I have 175 Orgs and 900,000 records and my real count query includes an iif that only returns a partial count based on other columns.
The db that I am taking over uses a recordset and loop to update. I am trying to write this in one SQL update statement. I have tried several variations of nested select statements but can't quite figure it out. Any help would save my brain from exploding. Thanks!
Assuming, that id is the unique ID of the row, you could use a correlated subquery to select the count of row IDs of the rows sharing the current organization, that are less than or equal to the current row ID and check, that this count is less than or equal to the number of records from that organization you want to designate.
For example to mark 3 records of the organization 100 you could use:
UPDATE test
SET sample = 'x'
WHERE org = 100
AND (SELECT count(*)
FROM test t
WHERE t.org = test.org
AND t.id <= test.id) <= 3;
And analog for the other cases.
(Disclaimer: I don't have access to Access (ha, ha, pun), so I could not test it. But I guess it's basic enough, to work in almost every DBMS, also in Access.)

what's the difference between SQL's

I work with Databases not extensively but to the point where I can write Selects, update's ,small joins etc..
I can get my work done with my current knowledge. I have encountered some difficulty while trying to complete a task, I got the task completed but would like to understand why some of the SQL's that I have written in process did not work.
Task at hand: I have a table "TESTTABLE" that has 5 columns and the 6th is the sum of these 5 columns.
Currently table looks like below:
ID NAME SUB1 SUB2 SUB3 SUB4 SUB5 TOTAL
1 VA 10 20 30 40 50
2 MI 20 40 60 80 10
3 NC 10 30 50 70 90
4 SC 10 20 30 40 50
5 WA 20 40 60 80 15
the last column 'Total' is currently empty.
Now,I need to update the total column in the table with the sum(sub1+sub2=sub3+sub4+sub5).
In this process I have written the following SQL's and it did work, would like to understand the difference.
Attempt1:
UPDATE TESTTABLE T
SET Total =
SELECT (sub1+sub2+sub3+sub4+sub5)
FROM TESTTABLE TB
WHERE T.ID = TB.ID);
Error encountered:--ERROR: (2) This form of correlated query is not supported - consider rewriting;
Attempt2:
CREATE TABLE TEMP_TESTTABLE AS( SELECT ID, SUM(sub1+sub2+sub3+sub4+sub5) AS SUB_TOTAL FROM TESTTABLE )
UPDATE TESTTABLE A
SET TOTAL =
(SELECT SUB_TOTAL
FROM TEMP_TESTTABLE B
WHERE B.ID=A.ID);
ERROR encountered: ERROR: (2) This form of correlated query is not supported - consider rewriting
Attempt3:
UPDATE TESTTABLE
SET TOTAL = SUM(sub1+sub2+sub3+sub4+sub5);
ERROR encountered: ERROR: Aggregate functions not allowed in the set list of an UPDATE statement
Attempt4- Successful one;
UPDATE TESTTABLE A
SET TOTAL = B.SUB_TOTAL FROM TEMP_TESTTABLE B
WHERE A.ID=B.ID
Attempt 4 worked for me by using the temp table created in attempt2 [TEMP_TESTTABLE].
I need some detail explanation, and appreciate if anyone can provide me and let me know how my attempt4 is different than 1,2,3.
Help is greatly appreciated.
Thanks,
Attempt1 failed because subqueries should be enclosed in parentheses.
UPDATE TESTTABLE T
SET Total =
(SELECT (sub1+sub2+sub3+sub4+sub5)
FROM TESTTABLE TB
WHERE T.ID = TB.ID);
Attempt2 failed because SUM() function is aggregate function, to sum values from multiple rows, not to sum values from multiple columns in one row.
You should redefine the column as a computed column, like this
Alter table TESTTABLE
add column Total as sub1+sub2+sub3+sub4+sub5
This is the cannonical Soluion.
UPDATE
TESTTABLE
SET
Total = (sub1+sub2+sub3+sub4+sub5)
The reason the others failed is that you where doing subselects that returned multiple rows. You didn't tell the UPDATE how the different rows mapped from the select to the UPDATE.
In this version you are making it simple - one table - on each row set a value on that row based on the data in that row.
In your final version you're doing the same but in a redundant way (extra join that does nothing).

Display more than one row with the same result from a field

I need to show more than one result from each field in a table. I need to do this with only one SQL sentence, I donĀ“t want to use a Cursor.
This seems silly, but the number of rows may vary for each item. I need this to print afterwards this information as a Crystal Report detail.
Suppose I have this table:
idItem Cantidad <more fields>
-------- -----------
1000 3
2000 2
3000 5
4000 1
I need this result, using one only SQL Sentence:
1000
1000
1000
2000
2000
3000
3000
3000
3000
3000
4000
where each idItem has Cantidad rows.
Any ideas?
It seems like something that should be handled in the UI (or the report). I don't know Crystal Reports well enough to make a suggestion there. If you really, truly need to do it in SQL, then you can use a Numbers table (or something similar):
SELECT
idItem
FROM
Some_Table ST
INNER JOIN Numbers N ON
N.number > 0 AND
N.number <= ST.cantidad
You can replace the Numbers table with a subquery or function or whatever other method you want to generate a result set of numbers that is at least large enough to cover your largest cantidad.
Check out UNPIVOT (MSDN)
Another example
If you use a "numbers" table that is useful for this and many similar purposes, you can use the following SQL:
select t.idItem
from myTable t
join numbers n on n.num between 1 and t.Cantidad
order by t.idTtem
The numbers table should just contain all integer numbers from 0 or 1 up to a number big enough so that Cantidad never exceeds it.
As others have said, you need a Numbers or Tally table which is just a sequential list of integers. However, if you knew that Cantidad was never going to be larger than five for example, you can do something like:
Select idItem
From Table
Join (
Select 1 As Value
Union All Select 2
Union All Select 3
Union All Select 4
Union All Select 5
) As Numbers
On Numbers.Value <= Table.Cantidad
If you are using SQL Server 2005, you can use a CTE to do:
With Numbers As
(
Select 1 As Value
Union All
Select N.Value + 1
From Numbers As N
)
Select idItem
From Table
Join Numbers As N
On N.Value <= Table.Cantidad
Option (MaxRecursion 0);

In SQL, does a BETWEEN statement have to be of the form BETWEEN lowest AND highest?

For example, if I did:
SELECT * FROM Users WHERE UserId BETWEEN 100 AND 1
what would the results be?
Edit: Sorry, you're right, I should have specified. I didn't want to know the exact number of rows that would return, I just wanted to know if it would return rows that were between 1 and 100 or if it would return rows from min(UserId) to 1 and 100 to max(UserId).
a BETWEEN b AND c
is shorthand for
b <= a and a <= c
So BETWEEN 100 and 1 won't match anything.
This probably depends on your RDBMS, but why not just try it out? On MySQL, I get no rows from a BETWEEN 100 AND 1 query whereas I do get rows from asking for BETWEEN 1 and 100.