While answering a test i faced the following question, which i wasn't able to solve:
Given the following table Z and query:
Table Z:
| Value |
---------
| 1 |
| 2 |
| 3 |
| 4 |
---------
Query:
UPDATE Z
SET VALUE = Y.VALUE + 1
FROM Z AS Y
WHERE Y.VALUE = Z.VALUE + 1;
SELECT SUM(VALUE) FROM Z;
The question asks for the result of this query execution. The question doesn't mention a specific SQL language.
The CORRECT answer is 16.
I don't know how this query can achieve this result. I wasn't even able to execute this query in a real environment, it complains about some syntax error near "FROM".
1 - Do you guys know how this query works?
2 - How could i proceed in order to execute this query?
P.S. I had a hard time trying to find some information about the FROM clause inside the UPDATE query.
One database where the code will work is Postgres. According to RexTester, this is indeed the answer.
The reason should be because you are adding "2" to each matching Z value: z = y.value + 1 = z.value + 1 + 1 -- but the fourth value does not match. Postgres generates the following:
value
1 4
2 3
3 4
4 5
This is the same data just in a different order.
With a similar statement, SQL Server does the right thing:
UPDATE Z
SET val = Y.val + 1
FROM Z, Z AS Y
WHERE Y.val = Z.val + 1;
(I am using the dreaded comma in a FROM clause to keep the two statements as similar as possible.)
It returns:
val
1 3
2 4
3 5
4 4
The two result sets are the same, they are just in a different order.
I hope this could help (made on MSSQL):
The first SELECT will show you original values the the update will use.
I made UPDATE inside transaction / rollback so it will not change the table. You can delete BEGIN TRAN and ROLLBACK TRAN if you want to change your data table.
CREATE TABLE TZ (VALUE INT)
INSERT INTO TZ VALUES (1),(2),(3),(4)
SELECT Z.VALUE AS Z_VALUE, Y.VALUE AS Y_VALUE
FROM TZ Z
INNER JOIN TZ Y ON Y.VALUE=Z.VALUE +1
;
BEGIN TRAN
UPDATE Z SET VALUE=Y.VALUE+1
FROM TZ Z
INNER JOIN TZ Y ON Y.VALUE=Z.VALUE +1
;
SELECT * FROM TZ;
SElECT SUM(VALUE) AS TOT FROM TZ;
ROLLBACK TRAN
Output first SELECT:
Z_VALUE, Y_VALUE
1 , 2
2 , 3
3 , 4
Output of SELECT after UPDATE:
VALUE
3
4
5
4
So, SUM is actually 16
If this worked—and I'd not expect it to on every database—this might help illustrate what's going on. Y is just an alias of Z. This table represents the joining of the tables during the update and the final results:
Z values Y (alias) joined on Z + 1 Update Value Z following update
======== ========================= ============ ==================
1 NO MATCH
1 2 3 3
2 3 4 4
3 4 5 5
4 NO MATCH 4
(SUM: 16)
Related
I am looking for a clean solution to perform calculation from a single column with a few conditions and insert it in the same table. My existing solution is to use a while loop with many variable declarations, writing simple query to store value, perform calculation and finally insert it as a new row to the table. However it looks messy and complicated. I am wondering if there is a better solution to it?
Original Table
Week | Indicator | Value
1 A 2
1 B 3
1 D 10
1 E 5
1 X 12
1 Y 6
2 A 4
2 B 5
2 D 7
2 E 3
2 X 4
2 Y 2
...
53
Updated Table
Week | Indicator | Value
1 A 2
1 B 3
1 C 5
1 D 10
1 E 5
1 F 5
1 X 12
1 Y 6
1 Z 2
2 A 4
2 B 5
2 C 9
2 D 7
2 E 3
2 F 4
2 X 4
2 Y 2
2 Z 2
In this example in the updated table, every 3rd row involves different calculation for the same week such that the 3rd row is an addition, 6th row is a subtraction and the 9th row is a division.
The calculation does not restrict to only addition and could include other forms of calculation formulas. I am just using addition as a simple illustration.
Here is an example of my SQL solution:
DECLARE #total_rows int;
SET #total_rows = (SELECT COUNT(*) FROM original_table);
DECLARE #wk varchar(5);
DECLARE #indicator1 char(1);
DECLARE #indicator2 char(1);
SET #indicator1 = 'A';
SET #indicator2 = 'B';
DECLARE #a_value int;
DECLARE #b_value int;
DECLARE #cal_value int;
DECLARE #iteration int
SET #iteration = 1
WHILE #iteration <= #total_rows
BEGIN
IF #iteration <= 53
SET #wk = concat('W',#iteration)
SET #a_value = (SELECT value
FROM original_table
WHERE indicator = #indicator1 and week = #wk);
SET #b_value = (SELECT value
FROM original_table
WHERE indicator = #indicator2 and week = #wk);
SET #cal_value = (#a_value/ NULLIF(#b_value,0)) *1000000;
....
SET #iteration = #iteration + 1
END
Not going to post the entire SQL script as it is quite lengthy but I hope you get the gist of it.
Is this not as simple as INSERT and SUM..?
INSERT INTO dbo.YourTable ([Week],Indicator,[Value])
SELECT YT.[Week],
'C' AS Indicator,
SUM(YT.[Value]) AS [Value]
FROM dbo.YourTable YT
GROUP BY YT.[Week];
DB<>Fiddle
I currently have a table with a quantity in it.
ID Code Quantity
1 A 1
2 B 3
3 C 2
4 D 1
Is there anyway to write a sql statement that would get me
ID Code Quantity
1 A 1
2 B 1
2 B 1
2 B 1
3 C 1
3 C 1
4 D 1
I need to break out the quantity and have that many number of rows
Thanks
Here's one option using a numbers table to join to:
with numberstable as (
select 1 AS Number
union all
select Number + 1 from numberstable where Number<100
)
select t.id, t.code, 1
from yourtable t
join numberstable n on t.quantity >= n.number
order by t.id
Online Demo
Please note, depending on which database you are using, this may not be the correct approach to creating the numbers table. This works in most databases supporting common table expressions. But the key to the answer is the join and the on criteria.
One way would be to generate an array with X elements (where X is the quantity). So for rows
ID Code Quantity
1 A 1
2 B 3
3 C 2
you would get
ID Code Quantity ArrayVar
1 A 1 [1]
2 B 3 [1,2,3]
3 C 2 [2]
using a sequence function (e.g, in PrestoDB, sequence(start, stop) -> array(bigint))
Then, unnest the array, so for each ID, you get a X rows, and set the quantity to 1. Not sure what SQL distribution you're using, but this should work!
You can use connect by statement to cross join tables in order to get your desired output.
check my solution it works pretty robust.
select
"ID",
"Code",
1 QUANTITY
from Table1, table(cast(multiset
(select level from dual
connect by level <= Table1."Quantity") as sys.OdciNumberList));
Added more information to clear up some confusions. Thanks.
I am trying to group sets of values in SQL. I have the following table and trying to somehow get the results as shown in the following table. I have explored group sets in SQL 2008, cubes, basic group by clauses, but I am not able to figure out the SQL query. Can someone please help. You can change the end resultant table format if you want but the basic idea is about how to count similar sets of values. In this table a,b,c exists 2 times so the count is 2 and x,y exists 3 times so the count is 3 and x, y, z exists 1 time so the count is 1. Please help.
UserId ProductId
1 a
1 b
1 c
2 x
2 y
3 x
3 y
4 x
4 y
5 a
5 b
5 c
6 x
6 y
6 z
ProductId Count
a 2
b 2
c 2
x 3
y 3
x 1
y 1
z 1
SELECT COUNT(`ProductId`),`ProductId ` WHERE 1 GROUP BY `ProductId` ORDER BY `ProductId` ASC
SELECT ProductId, COUNT(UserId) AS NbrOfUsers
FROM TABLE_NAME
GROUP BY ProductId, COUNT(UserId)
You're selecting ProductId & the count of how many UserId exist for that ProductId.
GROUP BY ProductId will group your counted UserId based on ProductId and also display the count as NbrOfUsers.
Your output will look like this:
ProductId NbrOfUsers
a 2
b 2
c 2
x 3
y 3
We have a table like this:
id mid mult tr result
----------------------------
1 1 1,35 0 1
2 1 5,85 0 2
3 1 4 1 X
50 2 1,3 1 1
51 2 7 0 2
52 2 4 0 X
99 3 2,45 0 1
100 3 2,2 0 2
101 3 3,3 1 X
105 4 2,3 0 1
106 4 2,4 0 2
107 4 3,2 1 X
111 5 3 1 1
112 5 1,9 0 2
113 5 3,25 0 X
What we need is a query that will bring us a table which will count how many times before, for a specific mid(match), have the same mults(multipliers) for result = 1 and result = x have occurred and group them so that we can count them. Something like
select mult(where result = 1), mult(where result = x), count(1)
The result will be like this
mult_1 mult_x count
------------------------------
1,35 4 33
1,3 4 112
The above states that we have seen 33 matches where the mult for result = 1 was 1,35 AND mult for result = x was 4. Also, we found 112 matches where multi for result = 1 was 1,3 AND for result = x mult was 4 (results are not dependant on the first table).
I find it rather complex myself, but hopefully I made sense. I use SQL Server 2008, so any method is more than welcome.
Here is my (final) solution in action: http://www.sqlfiddle.com/#!3/3a516/7
There are a number of assumptions I'm making here.
I'm assuming that every mid value is going to have at most 1 result value of '1' and 1 result of '2'.
I'm assuming that if you want to specify a mid and have the query run off of that.
This assumption turned out to be wrong.
I'm assuming that you want to include the data for the mid you specify.
This assumption turned out to be wrong, it was every match.
I'm assuming that you want to include every mid (or match) before the mid you specify.
This assumption turned out to be wrong, it was every match.
I'm assuming that for any mult_1 and mult_x combination you find in this way, you want the count of how many times that combination occurs, even if it occurs after the match(mid) that you specified.
This assumption turned out to be wrong, it was just for every match.
If all of these assumptions sound right, then this might create the result you're looking for:
DECLARE #Mid INT = 2
;WITH MatchResults AS
(
SELECT
Mid
, [1] AS MultWithResult1
, [X] AS MultWithResultX
FROM
(
SELECT
Mid
, mult
, result
FROM Matches
WHERE result IN ('1', 'X')
) Base
PIVOT
(
MAX(mult)
FOR result
IN
(
[1]
, [X]
)
) Pivoted
)
SELECT
mult.MultWithResult1 AS mult_1
, mult.MultWithResultX AS mult_x
, COUNT(*) AS [count]
FROM MatchResults mult
GROUP BY mult.MultWithResult1
, mult.MultWithResultX
EDIT: I have edited it based on the response to my answer to what I think he means.
Use this query:
select mult_1, mult_x, count() as count
from Matches M
inner join (select distinct M1.mult as mult_1, MX.mult as mult_x from
matches as M1, matches as MX
where M1.result=1 and MX.result=x) M1x
on (M.mult=M1x.mult_1 and M.result=1) or (M.mult=M1x.mult_x and result=x)
group by mult_1, mult_x
EDIT:
I'm supposing you wnat to get the count of all possible combinations of multipliers of matches with result=1 and matches with result = x.
If this is the case, M1x gives all this possible combinations. And you join all the possible matchea with have any of those combinations, and count them, grouping by the possible set of combinations defined by M1x.
I've got a simple problem that really has me stumped.
I have a master table Table X
Table X
ID
_________
1
2
3
4
5
I have a join table for Table X that allows records to be self joined. Let's call this JoinTableX
JoinTableX
RecordAID RecordBID
--------- --------
1 2 (So Record 1 from Table X has a link to Record 2 from Table X)
1 3
1 4
2 3
2 4
3 1
3 2
4 1
4 2
So how do I write a SQL query to show me all the records in JoinTableX that have a duplicate dependency on each other (example bove Table X Record 1 is linked to Table X Record 4 and Table X Record 4 is linked to Table X Record 1.
select *
from JoinTableX a
inner join JoinTableX b on a.RecordAID = b.RecordBID
and a.RecordBID = b.RecordAID
(SELECT RecordAID, RecordBID FROM JoinTableX)
INTERSECT
(SELECT RecordBID, RecordAID FROM JoinTableX)