add specific multiple rows (SQL) - sql

I am new to SQL and I want to write a query to add multiple rows in a table.
For example:
Table:
matchid|player1id|player2id|player1score|player2score
101 |20 |10 |0 |100
101 |20 |10 |0 |100
101 |20 |10 |0 |100
201 |20 |10 |645 |0
201 |20 |10 |100 |700
201 |20 |10 |0 |100
Required output:
matchid|player1id|player2id|player1score|player2score
101 |20 |10 |0 |300
201 |20 |10 |745 |800
Note: I have to do this without using GROUP BY

Without using GROUP BY:
SELECT *
FROM (
SELECT DISTINCT matchid, player1id, player2id FROM tbl
) AS t
CROSS APPLY(
SELECT
SUM(player1score), SUM(player2score)
FROM tbl
WHERE
matchid = t.matchid
AND player1id = t.player1id
AND player2id = t.player2id
) AS x(player1score, player2score)

select matchid,player1id,player2id,SUM(player1score) as
player1score,SUM(player2score) as player2score
FROM table1
Group by player1id,player2id, matchid

SELECT
matchid, player1is, player2id,
SUM(player1score) as player1score,
SUM(player2score) as player2score
FROM
tablename
GROUP BY
matchid, player1id, player2id

Does this satisfy the requirement?:
select
matchid, player1id, player2id,
(select sum(player1score from Table t2 where t2.matchid = t.matchid) as player1score,
(select sum(player2score from Table t2 where t2.matchid = t.matchid) as player2score
from
(select distinct matchid, player1id, player2id from Table) t

Related

Why do my distinct functions not work in Oracle?

In my student table I have some student's imformation.
id |phone |name |age |sex
---|-------------|------- |-------|-------
1 |13553841211 |name1 |11 |1
2 |13553841212 |name2 |12 |0
3 |13553841213 |name3 |13 |1
4 |13553841214 |name4 |14 |0
5 |13553841214 |name5 |15 |1
Now I want to select all the information. If the count of the phone is greater than 1, I want to return only one row whose id is max.
I want the result :
id |phone |name |age |sex
---|-------------|------- |-------|-------
1 |13553841211 |name1 |11 |1
2 |13553841212 |name2 |12 |0
3 |13553841213 |name3 |13 |1
5 |13553841214 |name5 |15 |1
My code is here, what's wrong?
select name,phone,id from student where
id in (select max(id) from student having count(phone)>=1);
select name,distinct(phone),id from student;
Try this
select *
from
(
select name, id, phone, age, sex, row_number() over(partition by phone order by id desc) as stu_ord
from student
)
where stu_ord = 1
TRY This:
SELECT t1.*
FROM STUDENT t1
INNER JOIN (
SELECT MAX(ID) as ID,phone
FROM student
GROUP BY phone
)t2
ON t1.ID =t2.ID
Try this:
SELECT name,phone,id
FROM student s1
WHERE NOT EXISTS
(SELECT 'next'
FROM student s3
WHERE s3.phone = s1.phone
AND s3.id > s1.id)

Query Results For Consecutive Months In Column Grouped By Value

The following is sample data:
Name | Hours | RDate | Company |
------------------------------------
A |0 |2014-08-01 |W
A |0 |2014-07-01 |W
A |0 |2014-06-01 |W
A |0 |2014-05-01 |W
B |0 |2014-08-01 |X
C |0 |2014-07-01 |Y
C |0 |2014-06-01 |Y
D |0 |2014-08-01 |V
D |0 |2014-07-01 |Z
The following are the results I desire:
Name | Hours | RDate | Company |
------------------------------------
A |0 |2014-08-01 |W
A |0 |2014-07-01 |W
A |0 |2014-06-01 |W
A |0 |2014-05-01 |W
C |0 |2014-07-01 |Y
C |0 |2014-06-01 |Y
So the question is:
How do I get the results only of which RDate is consecutive months in the columns I.e 2014-08-01, 2014-07-01(2014-08-01, 2014-06-01 would not satisfy)for the same name and the same company
I'm thinking this is somewhat a variation of Grouping Islands of Contiguous Dates problem.
;WITH Cte AS(
SELECT *,
RN = DATEADD(MONTH, - ROW_NUMBER() OVER (PARTITION BY Name, Company ORDER BY RDate), RDate)
FROM Test
)
,CteCount AS(
SELECT *,
CC = COUNT(*) OVER(PARTITION BY Name, Company, RN)
FROM Cte
)
SELECT
Name, Hours, RDate, Company
FROM CteCount
WHERE CC > 1
SQL FIDDLE
Although #wewesthemenace answers is way more efficient, I tried to figure out myself with solution I was working on and it works; Keeping previously marked answer as marked because is way better. This actually works as well:
SELECT
one.*
FROM
foo one
INNER JOIN
foo two
ON
(one.Name = two.Name and one.Company = two.Company)
WHERE
CONVERT(int,FORMAT(two.Date, 'yyyyMM')) - CONVERT(int,FORMAT(one.ACSS_Date, 'yyyyMM')) = 1
ORDER BY
one.Name
,one.Date DESC

Complicated min/max multi-table query

I need to get the min and max score of group ids, but only if they are enabled:
cdu_group_sl: cdu_group_cc: cdu_group_ph:
-------------------- -------------------- --------------------
|id |name |enabled | |id |name |enabled | |id |name |enabled |
-------------------- -------------------- --------------------
|1 |sl_1 |1 | |1 |cc_1 |1 | |1 |ph_1 |0 |
|2 |sl_3 |1 | |2 |cc_2 |0 | |2 |ph_2 |1 |
|3 |sl_4 |1 | |3 |cc_3 |1 | |3 |ph_3 |1 |
-------------------- -------------------- --------------------
Scores are found in a separate table:
cdu_user_progress
----------------------------------
|id |group_type |group_id |score |
----------------------------------
|1 |sl |1 |50 |
|1 |cc |1 |10 |
|1 |ph |1 |20 |
|1 |sl |2 |80 |
|1 |sl |3 |20 |
|1 |cc |3 |30 |
|1 |sl |1 |40 |
|1 |ph |1 |50 |
|1 |cc |1 |40 |
|1 |ph |2 |90 |
----------------------------------
I need to get a max and min score for each type of group for only enabled groups (for each type):
---------------------------------------------
|group_type |group_id |min_score |max_score |
---------------------------------------------
|sl |1 |40 |50 |
|sl |2 |80 |80 |
|sl |3 |20 |20 |
|cc |1 |10 |40 |
|cc |3 |30 |30 |
|ph |1 |20 |50 |
|ph |2 |90 |90 |
---------------------------------------------
Any idea what the query might be??? So far I have:
SELECT * FROM cdu_user_progress
JOIN cdu_group_sl ON (cdu_group_sl.id = cdu_user_progress.group_id AND cdu_user_progress.group_type = 'sl')
JOIN cdu_group_cc ON (cdu_group_cc.id = cdu_user_progress.group_id AND cdu_user_progress.group_type = 'cc')
JOIN cdu_group_ph ON (cdu_group_ph.id = cdu_user_progress.group_id AND cdu_user_progress.group_type = 'ph')
WHERE cdu_user_progress.uid = $student->uid
AND (cdu_user_progress.group_type = 'sl' AND cdu_group_sl.enabled = 1)
AND (cdu_user_progress.group_type = 'cc' AND cdu_group_cc.enabled = 1)
AND (cdu_user_progress.group_type = 'ph' AND cdu_group_ph.enabled = 1)
Probably completely wrong...
what about using a union to pick the groups you are interested in - something like:
select group_type, group_id min(score) min_score, max(score) max_score
from (
select id, 'sl' grp from cdu_group_sl where enabled = 1
union all
select id, 'cc' from cdu_group_cc where enabled = 1
union all
select id, 'ph' from cdu_group_ph where enabled = 1
) grps join cdu_user_progress scr
on grps.id = scr.group_id and grps.grp = scr.group_type
group by scr.group_type, scr.group_id
The following is probably the fastest way to do this query. To optimize this, you should have an index on group_id, enabled on each of the three "sl", "cc", and "ph" tables:
select cup.*
from cdu_user_progress cup
where (cup.group_type = 'sl' and
exists (select 1
from cdu_group_sl sl
where sl.id = cup.group_id and
sl.enabled = 1
)
) or
(cup.group_type = 'cc' and
exists (select 1
from cdu_group_cc cc
where cc.id = cup.group_id and
cc.enabled = 1
)
) or
(cup.group_type = 'ph' and
exists (select 1
from cdu_group_ph ph
where ph.id = cup.group_id and
ph.enabled = 1
)
)
As a note, having three tables with the same structure is usually a sign of a poor database schema. These three tables should probably be combined into a single table, which would make this query much easier to write.
If you are just starting up this project, I would recommend refining your data structure. Based on what you showed, you could benefit from only one cdu_groups table with a reference to a new cdu_group_types table, and removing the group_type column from cdu_user_progress.
If this is an established project, where changing the structure would be too disruptive... then one of the other answers showing a query would be a better/easier fit.
Otherwise, you could simplify things with restructured tables and end up with a query like:
SELECT group_type,
group_id,
MIN(score) as min_score,
MAX(score) as max_score
FROM cdu_user_progress c
INNER JOIN cdu_groups g
ON c.group_id=g.id
INNER JOIN cdu_group_types t
ON g.group_type_id=t.id
WHERE enabled=1
GROUP BY group_type, group_id
This is shown, with expected results, in this SQLFiddle. With this structure you can add new group types as you want (and also cut down on amount of tables and joins). Tables would be (simplified in this code below, no FKs or anything):
CREATE TABLE cdu_user_progress
(id INT, group_id INT, score INT)
CREATE TABLE cdu_group_types
(id INT, group_type VARCHAR(3))
CREATE TABLE cdu_groups
(id INT, group_type_id INT, name VARCHAR(10), enabled BIT NOT NULL DEFAULT 1)
Granted moving data to a new structure may be a pain or not reasonable... but wanted to throw this out there as a possibility or just something to chew on.

How to compare each row against each other and get the best result?

Suppose I have a table of values and categories:
+--+-----+---+
|ID|value|cat|
+--+-----+---+
|0 |1 |0 |
+--+-----+---+
|1 |3 |0 |
+--+-----+---+
|2 |2 |1 |
+--+-----+---+
|3 |1.2 |1 |
+--+-----+---+
|4 |1 |1 |
+--+-----+---+
And I want to know, for each row, the ID of the row which matches the value most closely and belongs to the same category, and I also want to know the difference.
So for row ID=0 the correct answer would be ID=1, and the difference value would be 2. The correct output would be this:
+--+----------+----------+
|ID|difference|best match|
+--+----------+----------+
|0 |2 |1 |
+--+----------+----------+
|1 |2 |0 |
+--+----------+----------+
|2 |0.8 |3 |
+--+----------+----------+
|3 |0.2 |4 |
+--+----------+----------+
|4 |0.2 |3 |
+--+----------+----------+
I'm just learning about CROSS JOIN and while I'm sure this can be done I don't really know where to start.
You can do this with a self-join and making use of the ROW_NUMBER() function in conjunction with MIN():
;WITH cte AS (SELECT a.ID aID
,MIN(ABS(a.value - b.value)) diff
,ROW_NUMBER() OVER(PARTITION BY a.ID ORDER BY MIN(ABS(a.value - b.value)))RN
,b.ID bID
FROM Table1 a
JOIN Table1 b
ON a.cat = b.cat
AND a.ID <> b.ID
GROUP BY a.ID,b.ID)
SELECT aID
,diff
,bID Best_Match
FROM cte
WHERE RN = 1
Demo: SQL Fiddle
If you want to return multiple rows in case of a tie, you'd want to use RANK() instead of ROW_NUMBER()

count and distinct over multiple columns

I have a database table containing two costs. I want to find the distinct costs over these two columns. I also want to find the count that these costs appear. The table may look like
|id|cost1|cost2|
|1 |50 |60 |
|2 |20 |50 |
|3 |50 |70 |
|4 |20 |30 |
|5 |50 |60 |
In this case I want a result that is distinct over both columns and count the number of times that appears. So the result I would like is
|distinctCost|count|
|20 |2 |
|30 |1 |
|50 |4 |
|60 |2 |
|70 |1 |
and ideally ordered
|disctinCost1|count|
|50 |4 |
|60 |2 |
|20 |2 |
|70 |1 |
|30 |1 |
I can get the distinct over two columns by doing something like
select DISTINCT c FROM (SELECT cost1 AS c FROM my_costs UNION SELECT cost2 AS c FROM my_costs);
and I can get the count for each column by doing
select cost1, count(*)
from my_costs
group by cost1
order by count(*) desc;
My problem is how can I get the count for both columns? I am stuck on how to do the count over each individual column and then add it up.
Any pointers would be appreciated.
I am using Oracle DB.
Thanks
By combining your two queries..
select cost, count(*)
from
(
SELECT id, cost1 AS cost FROM my_costs
UNION ALL
SELECT id, cost2 AS c FROM my_costs
) v
group by cost
order by count(*) desc;
(If when a row has cost1 and cost2 equal, you want to count it once not twice, change the union all to a union)
You can use the unpivot statement :
select *
from
(
SELECT cost , count(*) as num_of_costs
FROM my_costs
UNPIVOT
(
cost
FOR cost_num IN (cost1,cost2)
)
group by cost
)
order by num_of_costs desc;