Get result using two tables without using any loop - sql

I have two tables Temp_Test and Temp_Marks.
Temp_Test is having following columns
id UserId QId QTitle QMarks
1 A1 1 A 5
2 A1 2 B 6
3 A1 3 C 4
4 A1 4 D 5
5 B3 1 A 8
6 B3 2 B 6
7 B3 3 C 4
8 B3 4 D 3
9 Z9 1 A 2
10 Z9 2 B 7
11 Z9 3 C 9
12 Z9 4 D 3
and Temp_Marks has following Columns
Id Score A B C D
1 1 10 5 40 12
2 2 20 10 50 23
3 3 30 15 60 34
4 4 40 20 70 54
5 5 50 25 80 84
6 6 60 30 90 36
7 7 70 35 10 85
8 8 80 40 20 97
9 9 90 45 30 58
10 10 100 50 100 48
I want to fetch result of particular UserId.
eg. If for A1, QTitle is A and marks is 5 in Temp_test table then fetch record from Column A where Score is 5 from Temp_Marks table.
without using while loop want to fetch all records of particular UserId or UserIds.
Can anyone help on this?

You may want to UNPIVOT the Temp_Marks first to easily join it with Temp_Test, and then PIVOT the result to achieve the desired format:
;WITH CteUnpivotedMarks AS(
SELECT
ID, Score, Col = 'A', Value = A
FROM Temp_Marks
UNION ALL
SELECT
ID, Score, Col = 'B', Value = B
FROM Temp_Marks
UNION ALL
SELECT
ID, Score, Col = 'C', Value = C
FROM Temp_Marks
UNION ALL
SELECT
ID, Score, Col = 'D', Value = D
FROM Temp_Marks
)
SELECT
UserId = t.UserID,
A = MAX(CASE WHEN t.QTitle = 'A' THEN c.Value END),
B = MAX(CASE WHEN t.QTitle = 'B' THEN c.Value END),
C = MAX(CASE WHEN t.QTitle = 'C' THEN c.Value END),
D = MAX(CASE WHEN t.QTitle = 'D' THEN c.Value END)
FROM Temp_Test t
INNER JOIN CteUnpivotedMarks c
ON t.QTitle = c.Col
AND t.QMarks = c.Score
GROUP BY t.UserID
RESULT
UserId A B C D
---------- ----------- ----------- ----------- -----------
A1 50 30 70 84
B3 80 30 70 34
Z9 20 35 30 34

Related

Add entries of a table into rows of another table

I have two tables
table a:
ID VALUE_z
1 41
2 32
3 51
table b:
ID TYPE z
1 a 10
1 b 15
1 c 20
2 a 12
2 b 8
2 c 5
3 a 21
3 b 4
3 c 2
I want to add the rows from table a to the column VALUE in table b based on the ID. The result should look like this
table result:
ID TYPE VALUE
1 a 10
1 b 15
1 c 20
1 z 41
2 a 12
2 b 8
2 c 5
2 z 32
3 a 21
3 b 4
3 c 2
3 z 51
Try the following using INSERT INTO SELECT Statement:
insert into tableB
select ID, 'z', VALUE_z
from tableA
See demo

Update rows based on range around values without changing rows that are not initially within range

In a local SQLite (vs 3.29.0) database, there is a table with 3 columns (excluding the rowID). Two contain values, and one contains categories. I want to update the category based on a range around the values of one specific category. It needs to be possible that the category that is SET is the same category as the one that determines the range.
Example:
id
Value
Value2
Category
1
20
20
2
2
30
30
2
3
40
40
2
4
70
70
2
5
5
5
1
6
19
19
1
7
26
26
1
8
42
42
1
9
49
49
1
10
52
52
1
11
71
71
1
12
90
90
1
13
17
17
1
I want rows to be changed to category 2, based on a range of 4 around value and a range of 2 around value2. This should change only rows 6, 9 and 11:
id
Value
Value2
Category
1
20
20
2
2
30
30
2
3
40
40
2
4
70
70
2
5
5
5
1
6
19
19
2
7
26
26
1
8
42
42
2
9
49
49
1
10
52
52
1
11
71
71
2
12
90
90
1
13
17
17
1
My current SQL statement is:
UPDATE tablename
SET Category = 2
WHERE (Category != 2
AND EXISTS (
SELECT *
FROM tablename t
WHERE t.Category = 2
AND tablename.Value BETWEEN t.Value - 4 AND t.Value + 4
AND tablename.Value2 BETWEEN t.Value2 -2 AND t.Value2 +2)
);
of which the result is:
id
Value
Value2
Category
1
20
20
2
2
30
30
2
3
40
40
2
4
70
70
2
5
5
5
1
6
19
19
2
7
26
26
1
8
42
42
2
9
49
49
1
10
52
52
1
11
71
71
2
12
90
90
1
13
17
17
2
What appears to be happening is that due to row 6 changing to category 2, row 13 is now within range of the values of a row that is in category 2, and therefore is also assigned category 2. How do I change the statement so that the SET is only applied to the values that were within range initially?
See the demo for the example.
If your version of SQLite is 3.33.0+ you can use the join-like UPDATE...FROM syntax to perform a self join in the UPDATE statement:
UPDATE tablename AS t1
SET Category = t2.Category
FROM tablename AS t2
WHERE t2.Category = 2
AND t1.Category <> t2.Category
AND t1.Value BETWEEN t2.Value - 4 AND t2.Value + 4
AND t1.Value2 BETWEEN t2.Value2 - 2 AND t2.Value2 + 2;
For previous versions of SQLite, first create a temporary table with all the rows of the table with Category = 2:
CREATE TEMPORARY TABLE t AS
SELECT * FROM tablename WHERE Category = 2;
and then update the table:
UPDATE tablename
SET Category = 2
WHERE Category <> 2
AND EXISTS (
SELECT 1
FROM t
WHERE tablename.Value BETWEEN t.Value - 4 AND t.Value + 4
AND tablename.Value2 BETWEEN t.Value2 -2 AND t.Value2 + 2
);
See the demo.

In SQL, how to select minimum value of a column and group by other columns?

I have a lookup table below:
id ref order
1 6 0
2 6 0
3 7 0
5 34 0
6 33 0
6 255 1
9 12 0
9 80 1
12 7 0
12 76 1
13 10 0
15 12 0
16 6 0
16 7 1
17 6 1
17 63 0
18 7 0
19 7 1
19 75 0
20 6 0
20 63 1
So in the lookup table (tab_lkp), it has column [id] (the IDs of entities), [ref] (the reference id that points to other entities in another table) and [order] (tells the order of reference, smaller order means higher priority).
My expectation is that, for each of the IDs, only one ref with the smallest order is selected. My code is (by following Phil's answer):
select id
, ref
, min_order = min(order)
from [dbo].[tab_lkp]
group by id, ref
order by id, ref
But the code doesn't work for me, the results still contains multiple records for each of the IDs:
id ref order
1 6 0
2 6 0
3 7 0
5 34 0
6 33 0
6 255 1
9 12 0
9 80 1
12 7 0
12 76 1
13 10 0
15 12 0
16 6 0
16 7 1
17 6 1
17 63 0
18 7 0
19 7 1
19 75 0
20 6 0
20 63 1
Could you please let me know what is wrong with my code? And how should I achieve my goal?
From an ANSI sql approach:
select x2.id, x2.ref, x2.order
from MyTable x2
inner join
(
select id, min(order) as min_order
from MyTable
group by id
) x1
on x1.id = x2.id
and x1.min_order = x2.order
You would normally do this using row_number():
select t.*
from (select t.*, row_number() over (partition by id order by ref) as seqnum
from [dbo].[tab_lkp] t
) t
where seqnum = 1;
or by using a subquery that does exactly what you state that you want,
"for each of the IDs, only one ref with the smallest order is selected"
Select * from tab_lkp t
Where order =
(Select Min(order) from tab_lkp
where Id = t.Id)

See if all records in the same group are of accepted types

Consider the following table. Each document (id) belongs to a group (group_id).
-----------------------
id group_id value
-----------------------
1 1 A
2 1 B
3 1 D
4 2 A
5 2 B
6 3 C
7 4 A
8 4 B
9 4 B
10 4 B
11 4 C
12 5 A
13 5 A
14 5 A
15 6 B
16 6 NULL
17 6 NULL
18 6 D
19 7 NULL
20 8 B
1/ Each document has a value NULL, A, B, C or D
2/ If the documents in the same group all have either A or B as value, the group is completed
3/ In this case, the desired output would read:
---------------------
group_id completed
---------------------
1 0 <== because document 3 = D
2 1 <== all documents have either A or B as a value
3 0 <== only one document in the group, value C
4 1 <== all documents have either A or B as a value
5 1 <== all documents have value A
6 0 <== because of NULL values and value D
7 0 <== NULL
8 1 <== only one document, value B
IS it possible to query this resultset?
As I am not very experienced in SQL, any help would be appreciated!
Try this
SELECT [group_id],
CASE
WHEN Count(CASE WHEN [value] IN ( 'A', 'B' ) THEN 1 END) = Count(*) THEN 1
ELSE 0
END AS COMPLETED
FROM yourtable
GROUP BY [group_id]

count of matching rows and select 30 from each count group in hive

How do I count the matching rows for the below sample data
ID Attribute 1 Attribute 2
1 A AA
2 B CC
3 C BB
4 A AA
5 C BB
6 D AA
7 B AA
8 C DD
9 A AB
10 A AA
the out put should look like this
ID Attribute 1 Attribute 2 count(Attribute1+Attribute2)
1 A AA 3
2 B CC 1
3 C BB 2
4 A AA 3
5 C BB 2
6 D AA 1
7 B AA 1
8 C DD 1
9 A AB 1
10 A AA 3
and then select 50% of rows from each count group. ex : for the mtaching row (A,AA) I need to select only 2 occurances. which would give me the the ID (1 and 4)
Here is the query:
select * from (select product_category_id,
count(1) over (partition by product_category_id) cnt,
row_number() over (partition by product_category_id) rn
from products) p where rn <= 0.5 * cnt;
Here is the sample result, product_category_id, cnt and then row number. In your case you need to have your two attributes in partition by clause.
59 24 1
59 24 2
59 24 3
59 24 4
59 24 5
59 24 6
59 24 7
59 24 8
59 24 9
59 24 10
59 24 11
59 24 12
You can do with SQL query like this.
SELECT *,
(SELECT COUNT(*)
FROM table AS t2
WHERE t1.[Attribute1] = t2.[Attibute1]
AND t1.[Attribute2] = t2.[Attibute2]) AS 'count(Attribute1+Attribute2)'
FROM table AS t1