I always found it a supernatural phenomenon the magic used in SQL queries when involved within Selects Selects. I found it very funny when I got the email from Thiago, company intern here, a query about what I had done and sent him:
This method is its magical means, sounds like the kind of thing that “should not work but it works” when u look! Not cuz it makes no sense (pq is), pq but these databases to imply things much simpler than that… Ultimately, works, qdo same is not to seek for a specific codeam (as you did before), which is great. (Thiago)
The funny thing about this is that I also never stopped to think through how it worked, simply used. Yes, wore it like magic, but now decided to study the background for how this solves my problems and decided to share here with you.
Attention: If you do not know anything about computer, never heard of SQL, query and other terms in this article, can stop reading here because the business is too technical and boring! Rsrsr Eu, eg, could not read the second paragraph of text that talk about the last wall of the report.
To start, I will soon show the solution. Below is a SQL query that, for us today, consists of pure magic:
1: SELECT
2: a1.*
3: FROM
4: Acao a1
5: WHERE
6: a1.situacaoAcao <> 'E' AND
7: a1.dtAlteracaoAcao = (
8: SELECT
9: MAX(a2.dtAlteracaoAcao)
10: FROM
11: Acao a2
12: WHERE
13: a2.indAcaoOriginal = a1.indAcaoOriginal
14: )
What it does? Returns all the Shares not deleteand only the most current. Single born? Yes, it is exactly what I wanted.
To better understand, let's see the table structure Action:
Action |
---|
indAcao: int IDENTITY(1,1) |
nomeAcao: varchar(200) NOT NULL |
dtAlteracaoAcao: datetime NOT NULL |
situacaoAcao: char(2) NOT NULL |
indAcaoOriginal: int NULL |
*The point in this table observer, is the relationship between the self-field indAcaoOriginal to indAcao. An action is never updated. If you need some updating, a new record is created, with new information, but with the indAcaoOriginal pointing to the first action that was created. So, we have a history of updates Shares.
Knowing what you have in the bank, a lot of individual actions (indAcao) auto-related (indAcaoOriginal) with the original Action, the challenge was to bring all the latest Actions, in other words, with the last change date.
Debunking the Magic
Let's use the table below as an example of records. It is the return of the following query:
1: SELECT
2: a1.*
3: FROM
4: Acao a1
indAcao | nomeAcao | dtAlteracaoAcao | situacaoAcao | indAcaoOriginal |
---|---|---|---|---|
1 | Book | 16/03/2006 10:10 | AA | 1 |
2 | Reserve product | 17/03/2006 11:11 | A | 1 |
3 | Book Products | 17/03/2006 18:03 | AA | 1 |
4 | Point Data | 18/03/2006 10:10 | AA | 2 |
5 | Point Data | 18/03/2006 11:40 | A | 2 |
6 | Cadastrar Estatíguitar | 18/03/2006 18:00 | AA | 6 |
7 | Register Employee | 18/03/2006 18:20 | AA | 7 |
8 | Reveal Negative | 19/03/2006 09:00 | AA | 8 |
9 | Check stock | 19/03/2006 10:05 | AA | 9 |
10 | Check stock | 20/03/2006 10:10 | A | 9 |
11 | Check stock | 20/03/2006 13:00 | It | 9 |
12 | Reduce | 20/03/2006 14:15 | AA | 12 |
13 | Reduce Costs | 20/03/2006 15:30 | A | 12 |
14 | Reduce Costs | 20/03/2006 16:45 | AE | 12 |
15 | Firing Employees | 21/03/2006 20:33 | AA | 15 |
16 | Revise Budget | 22/03/2006 08:17 | AA | 16 |
17 | Cancel Contract | 22/03/2006 09:05 | AA | 17 |
18 | Sell Product | 22/03/2006 14:18 | AA | 18 |
19 | Sell Product | 22/03/2006 17:22 | A | 18 |
Filtering records by deletingtwo, we have the following result:
1: SELECT
2: a1.*
3: FROM
4: Acao a1
5: WHERE
6: a1.situacaoAcao <> 'E'
indAcao | nomeAcao | dtAlteracaoAcao | situacaoAcao | indAcaoOriginal |
---|---|---|---|---|
1 | Book | 16/03/2006 10:10 | AA | 1 |
2 | Reserve product | 17/03/2006 11:11 | A | 1 |
3 | Book Products | 17/03/2006 18:03 | AA | 1 |
4 | Point Data | 18/03/2006 10:10 | AA | 2 |
5 | Point Data | 18/03/2006 11:40 | A | 2 |
6 | Cadastrar Estatíguitar | 18/03/2006 18:00 | AA | 6 |
7 | Register Employee | 18/03/2006 18:20 | AA | 7 |
8 | Reveal Negative | 19/03/2006 09:00 | AA | 8 |
9 | Check stock | 19/03/2006 10:05 | AA | 9 |
10 | Check stock | 20/03/2006 10:10 | A | 9 |
12 | Reduce | 20/03/2006 14:15 | AA | 12 |
13 | Reduce Costs | 20/03/2006 15:30 | A | 12 |
14 | Reduce Costs | 20/03/2006 16:45 | AE | 12 |
15 | Firing Employees | 21/03/2006 20:33 | AA | 15 |
16 | Revise Budget | 22/03/2006 08:17 | AA | 16 |
17 | Cancel Contract | 22/03/2006 09:05 | AA | 17 |
18 | Sell Product | 22/03/2006 14:18 | AA | 18 |
19 | Sell Product | 22/03/2006 17:22 | A | 18 |
*Only action indAcao 11 was removed.
If you run the query below in isolation, we have the following result:
1: SELECT
2: MAX(a2.dtAlteracaoAcao)
3: FROM
4: Acao a2
indAcao | nomeAcao | dtAlteracaoAcao | situacaoAcao | indAcaoOriginal |
---|---|---|---|---|
19 | Sell Product | 22/03/2006 17:22 | A | 18 |
*The MAX function() returns the largest value of a field in a set, in this case isolated, set corresponds to all records of the table action. It returns the record 19 because it has the largest data.
Then, I need to do to rescue the largest data set of the Original Shares? I need to generate a separate set, containing all Original Shares, to rescue this largest data. This is obvious. It's good that we know what we want to define. The problem is to talk to SQL him understand that. :)
Let's run a Chinese, step-by-step, query to look at how the magic really works.
Step-by-Step
The first thing that makes the query below, rescue is different from the first record deletedo da tabela a1.
1: SELECT
2: a1.*
3: FROM
4: Acao a1
5: WHERE
6: a1.situacaoAcao <> 'E' AND
7: a1.dtAlteracaoAcao = (
8: SELECT
9: MAX(a2.dtAlteracaoAcao)
10: FROM
11: Acao a2
12: WHERE
13: a2.indAcaoOriginal = a1.indAcaoOriginal
14: )
indAcao | nomeAcao | dtAlteracaoAcao | situacaoAcao | indAcaoOriginal |
---|---|---|---|---|
1 | Book | 16/03/2006 10:10 | AA | 1 |
Having this record, the internal query below, creates the following subset:
1: SELECT
2: MAX(a2.dtAlteracaoAcao)
3: FROM
4: Acao a2
5: WHERE
6: a2.indAcaoOriginal = a1.indAcaoOriginal
indAcao | nomeAcao | dtAlteracaoAcao | situacaoAcao | indAcaoOriginal |
---|---|---|---|---|
1 | Book | 16/03/2006 10:10 | AA | 1 |
2 | Reserve product | 17/03/2006 11:11 | A | 1 |
3 | Book Products | 17/03/2006 18:03 | AA | 1 |
She rescues all records from the table action (a2) that have a2.indAcaoOriginal a1.indAcaoOriginal equal to the current record of the table action (a1). What is the value of the first record in a1.indAcaoOriginal rescued by Select external? The value is 1, then, returns all records that have the indAcaoOriginal a2 equals 1. Simple as that.
Having this subset (indAcaoOriginal = 1), select the internal returns, by MAX, most registered date, in this case, it is 17/03/2006 18:03.
Now, knowing that more time is 17/03/2006 18:03, select the external (a1), compares with the date of its registration.
indAcao | nomeAcao | dtAlteracaoAcao | situacaoAcao | indAcaoOriginal |
---|---|---|---|---|
1 | Book | 16/03/2006 10:10 | AA | 1 |
As we can verify, MAX on the date returned is not equal to date of our first record, in other words, the select will ignore this line, not displaying the, and go to the second record:
indAcao | nomeAcao | dtAlteracaoAcao | situacaoAcao | indAcaoOriginal |
---|---|---|---|---|
2 | Reserve product | 17/03/2006 11:11 | A | 1 |
Soon, here he will do the same steps explained above and verify that the date remains different from the date of the largest subset of the Original Shares.
Thus, select the entire table travel, returning only those records that possessrem the largest data.
Easy né? I'm feeling the Mr. M, to reveal the magic involved in this query. :)
And there Thiago, understood?
I will propose a challenge in SQL Server 2000. Consultation.
Certain employees received 1/3 of holidays in February and received family allowance in January, but did not receive family allowance in February.
Legal, but I usually use the IN which is the same! =D
I know the article is old, but I had a big problem to do a procedure that return me the last date of a group of records. Congratulations for the article and thanks, helped me solve the problem and understand how it works! =)
Hug.
TABELA R1
A B C
1 a w
5 c x
1 c in
3 c p
1 d w
2 b y
2 C
4 c q
3 b p
2 a y
5 a y
4 a q
3 a p
5 b x
1 b w
TABELA R2
B
a
b
c
Obs: uppercase letters "ABC" are the column(field) R1 table and column B is the(field) da Tabela R2. Examples: 1º Line R1 is 1AW = ABC and R2 is B = a
Who can do the same explanation for the tables R1 and R2:
R1 A B C R2 B
1 a w a
5 c x b
1 c in the c
3 c p
1 d w
2 b y
2 C
4 c q
3 b p
2 a y
5 a y
4 a q
3 a p
5 b x
1 b w
SELECT DISTINCT A
FROM R1 AS a
WHERE NOT EXISTS (SELECT * FROM R2 AS b
WHERE NOT EXISTS (SELECT * FROM R1 AS c
WHERE c.A = a.A
AND c.C = a.C
AND c.B = b.B));
Output:
A
1
3
Information is never too! I bet you that most people who program these days make use of SQL codes like the one above without knowing how they really work. Bruno told very well in his explanation. I came here looking on the subject of a SELECT inside another. Although I know the above method, I was even more inside of how it works. Congratulations!
My old, no pun intended, for the old man here is me. I 52 years. He was retired after working 12 years managing a department of informatics (exercised only knowledge management) I did some courses in logic, programming, administration of BD … and recently returned to the labor market – developing some applications, that utilizam subqueryes. Your article has brought the help I needed to understand what I was intuitively and to explain more properly to the rest who are in this task.
Congratulations!
Itamar
It's all right, Do not worry. Trainees sacaneados end one way or another… ¬_¬!
I do not care about that, just wanted to clarify my position a bit in this story, that was kind of vague…
'm Dying to finish this system tb!
Thiago:
It was not my intention to call him an idiot, so I explain there in the beginning I did not quite understand how it worked, I decided to study the whole thing step by step so I can understand. The funny all, was the phrase you wrote, as it is out of context purposeful, it is funny.
Did not want to call anyone a fool not.
AH! I have no peeve with trainees ehn! Alex who liked to treat bad! rsrsrsrs
Here is the clarification and an apology for the wrong impression interpreted by readers.
Hug and let's finish this system as soon as the deal is getting good! :)
vlw
On, talking so it seems until I'm stupid! Of course I understand why this works, simply puzzled by the SQL Server be smart to the point of running the subquery multiple times (one for each indAcaoOriginal), now I see him teasing things theoretically simpler.
Alex:
What I actually wrote is gibberish so, out of context. The thing is, I was making a VIEW that returns only the newest records do not deleteof all actions, and was using a method with GROUP BY. So Bruno showed me another method, with code like this aà upper.
I decided to try this method, but I realized that it it filtered in query result to an action especÃis (a1.indAcaoOriginal = XX in the first WHERE), and was surprised when the code worked for all of them, meaning that the subquery was performed several times, seeking more data per group AA‡The•ES, thing would not imagined, so called "magic".
You and trainees, home… 'll tell you! It seems that people are anta! Good, some may even be, but I assure you I do not! =)
Fala Alex!
Saw, when I was his intern you did not treat me well. Spoke only: If male. KKKKKKKKKKKKKKKKKKKK
How to explain the background, could have made an animation byte by traveling north and south bridge and CPU being processed in, stored in registers and being transformed into bits and stuff, but I thought it would stretch a little explanation… rsrsrsrs
As for what Thiago wrote, I think I will have to study thoroughly what he said and write another article, but I think this will be much more complex! lol
Peel are worth visiting!
*And only nerd to even get in here and read this… rsrs
Hug!
I can not believe you did all this because of a trainee!!!! Well, written as, Achaean interesting. Except that when you said it would deepen the subject, I thought it was to explain the workings of the DBMS in order to receive a query. AHUhaUhAuhauhaUHuaHuahUahua
ps. I read that Thiago wrote three times and so far not understood. I think we shouldamos reactivate Side B!
Alam:
Kkkkkkkkkkkkkk
Was to teach the trainee not. Was to understand even more deeply! lol
But now he will surely understand. lol
Thanks for the comment!
Ninja:
rsrsr I give articulista SQL Magazine? Would articulate various stories even, or else, write a raw SQL for Advanced Beginners! lol
Thanks to comment!
[]s
Sent well again!!!
I'll talk to my friend to put your article in SQL Magazine, vc is the newest writer for magazine…
If the trainee does not know SQL, tells him to take a course?!?!?! rs,rs,rs
All this to teach the Trainee SQL Query?