i have this table
table with evaluators and evaluatees.
Every row of the table above is a relationship between two people(First row:person a evaluates person b, Second row person a evaluates person c and so on).
I want to trasform this table into looking like this
Wanted Output
So Each row will correspond one evaluator and each column will be people being evaluated by him. (Because some evaluators have less people to evaluate than others the remaining columns for someone who doesnt have that many evaluatees will be NULL.
Many thanks hope you can help me out
Since you have SQL Server tag so, i would use row_number() function with conditional aggregation :
select evalutor,
max(case when seq = 1 then evalutee end) as evalutee1,
max(case when seq = 2 then evalutee end) as evalutee2,
max(case when seq = 3 then evalutee end) as evalutee3
from (select t.*, row_number() over (partition by evalutor order by evalutee) as seq
from table t
) t
group by evalutor;
Related
This question already has an answer here:
Write a MySQL query to get required result
(1 answer)
Closed 2 years ago.
I am working with MySQL database.
Table contains data like:
id
uaid
attribute
value
time
risk factor
1
1234
File Path
Exist
16123
NONE
2
1234
File Path
Not Exist
16124
CRITICAL
3
1234
File Path
Exist
16125
NONE
the required result should be like below:
Attribute
Risk Factor
UAID
Failed Value
Present Value
File Path
CRITICAL
1234
Not Exist
Exist
Explanation:
we need to show data which have risk factor critical.
Failed Value = at the time (latest one) when risk factor is critical then value for that attribute represent as failed value
Present value = it is represented as current value for that attribute in database.
i have tried with the solution of two sql queries. one for taking getting rows which have risk factor equal to critical. and the second one for getting current value of each unique attribuite. and then some formatting of data from the both queries.
I am looking for solution which removes the extra overhead of data formatting according to requirement.
Schema table(id,uaid,attribute,value,time,risk_factor)
One option, using ROW_NUMBER:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY uaid, attribute
ORDER BY time DESC) rn
FROM yourTable
)
SELECT
attribute,
'CRITICAL' AS `Risk Factor`,
uaid,
MAX(CASE WHEN `risk factor` = 'CRITICAL' THEN value END) AS `Failed Value`,
MAX(CASE WHEN rn = 1 THEN value END) AS `Present Value`
FROM cte
GROUP BY
attribute,
uaid
HAVING
SUM(`risk factor` = 'CRITICAL') > 0;
Assuming that a group is a rowset with the same (uaid, attribute) values:
WITH cte AS (
SELECT DISTINCT
attribute,
'CRITICAL' `Risk Factor`,
uaid,
FIRST_VALUE(value) OVER (PARTITION BY uaid, attribute
ORDER BY `risk factor` = 'CRITICAL' DESC, `time` DESC) `Failed Value`,
FIRST_VALUE(value) OVER (PARTITION BY uaid, attribute
ORDER BY `time` DESC) `Present Value`,
SUM(`risk factor` = 'CRITICAL') OVER (PARTITION BY uaid, attribute) is_critical
FROM source_table
)
SELECT Attribute, `Risk Factor`, UAID, `Failed Value`, `Present Value`
FROM cte
WHERE is_critical;
fiddle
I've studied and tried days worth of SQL queries to find "something" that will work. I have a table, apj32_facileforms_subrecords, that uses 7 columns. All the data I want to display is in 1 column - "value". The "record" displays the number of the entry. The "title" is what I would like to appear in the header row, but that's not as important as "value" to display in 1 row based upon "record" number.
I've tried a lot of CONCAT and various Pivot queries, but nothing seems to do more than "get close" to what I'd like as the end result.
Here's a screen shot of the table:
The output "should" be linear, so that 1 row contains 9 columns:
Project; Zipcode; First Name; Last Name; Address; City; Phone; E-mail; Trade (in that order). And the values in the 9 columns come from "value" as they relate to the "record" number.
I know there are LOT of examples that are similar, but nothing I've found covers taking all the values from "value" and CONCAT to 1 row.
This works to get all the data I want - SELECT record,value FROM apj32_facileforms_subrecords WHERE (record IN (record,value)) ORDER BY record
But the values are still in multiple rows. I can play with that query to get just the values, but I'm still at a loss to get them into 1 row. I'll keep playing with that query to see if I can figure it out before one of the experts here shows me how simple it is to do that.
Any help would be appreciated.
Using SQL to flatten an EAV model representation into a relational representation can be somewhat convoluted, and not very efficient.
Two commonly used approaches are conditional aggregation and correlated subqueries in the SELECT list. Both approaches call out for careful indexing for suitable performance with large sets.
correlated subqueries example
Here's an example of the correlated subquery approach, to get one value of the "zipcode" attribute for some records
SELECT r.id
, ( SELECT v1.value
FROM `apj32_facileforms_subrecords` v1
WHERE v1.record = r.id
AND v1.name = 'zipcode'
ORDER BY v1.value LIMIT 0,1
) AS `Zipcode`
FROM ( SELECT 1 AS id ) r
Extending that, we repeat the correlated subquery, changing the attribute identifier ('firstname' in place of 'zipcode'. looks like we we could also reference it by element, e.g. v2.element = 2
SELECT r.id
, ( SELECT v1.value
FROM `apj32_facileforms_subrecords` v1
WHERE v1.record = r.id
AND v1.name = 'zipcode'
ORDER BY v1.value LIMIT 0,1
) AS `Zipcode`
, ( SELECT v2.value
FROM `apj32_facileforms_subrecords` v2
WHERE v2.record = r.id
AND v2.name = 'firstname'
ORDER BY v2.value LIMIT 0,1
) AS `First Name`
, ( SELECT v3.value
FROM `apj32_facileforms_subrecords` v3
WHERE v3.record = r.id
AND v3.name = 'lastname'
ORDER BY v3.value LIMIT 0,1
) AS `Last Name`
FROM ( SELECT 1 AS id UNION ALL SELECT 2 ) r
returns something like
id Zipcode First Name Last Name
-- ------- ---------- ---------
1 98228 David Bacon
2 98228 David Bacon
conditional aggregation approach example
We can use GROUP BY to collapse multiple rows into one row per entity, and use conditional tests in expressions to "pick out" attribute values with aggregate functions.
SELECT r.id
, MIN(IF(v.name = 'zipcode' ,v.value,NULL)) AS `Zip Code`
, MIN(IF(v.name = 'firstname' ,v.value,NULL)) AS `First Name`
, MIN(IF(v.name = 'lastname' ,v.value,NULL)) AS `Last Name`
FROM ( SELECT 1 AS id UNION ALL SELECT 2 ) r
LEFT
JOIN `apj32_facileforms_subrecords` v
ON v.record = r.id
GROUP
BY r.id
For more portable syntax, we can replace MySQL IF() function with more ANSI standard CASE expression, e.g.
, MIN(CASE v.name WHEN 'zipcode' THEN v.value END) AS `Zip Code`
Note that MySQL does not support SQL Server PIVOT syntax, or Oracle MODEL syntax, or Postgres CROSSTAB or FILTER syntax.
To extend either of these approaches to be dynamic, to return a resultset with a variable number of columns, and variety of column names ... that is not possible in the context of a single SQL statement. We could separately execute SQL statements to retrieve information, that would allow us to dynamically construct a SQL statement of a form show above, with an explicit set of columns to be returned.
The approaches outline above return a more traditional relational model, (individual columns each with a value).
non-relational munge of attributes and values into a single string
If we have some special delimiters, we could munge together a representation of the data using GROUP_CONCAT function
As a rudimentary example:
SELECT r.id
, GROUP_CONCAT(v.title,'=',v.value ORDER BY v.name) AS vals
FROM ( SELECT 1 AS id ) r
LEFT
JOIN `apj32_facileforms_subrecords` v
ON v.record = r.id
AND v.name in ('zipcode','firstname','lastname')
GROUP
BY r.id
To return two columns, something like
id vals
-- ---------------------------------------------------
1 First Name=David,Last Name=Bacon,Zip Code=98228
We need to be aware that the return from GROUP_CONCAT is limited to group_concat_max_len bytes. And here we have just squeezed the balloon, moving the problem to some later processing, to parse the resulting string. If we have any equal signs or commas that appear in the values, it's going to make a mess of parsing the result string. So we will have to properly escape any delimiters that appear in the data, so that GROUP_CONCAT expression is going to get more involved.
I currently have the following SQL query:
SELECT video_calls.initiated_user_id AS user_id,
(CASE
WHEN EXISTS
(SELECT *
FROM patients
WHERE patients.id = video_calls.initiated_user_id)
THEN 'patient'
ELSE (CASE
WHEN EXISTS
(SELECT *
FROM backend_users
WHERE backend_users.id = video_calls.initiated_user_id)
THEN "%%backend%%"
ELSE "unknown"
END)
END) AS user_type
FROM video_calls
WHERE id='7f350a98-93d3-4d21-80a8-6cda3e47a4c0'
UNION
SELECT user_id,
user_type
FROM channel_joins
WHERE channel_id='7f350a98-93d3-4d21-80a8-6cda3e47a4c0'
In the line, where it currently says THEN "%%backend%%" I'd like to return the column backend_users.backend_type instead, for the corresponding row where the value video_calls.initiated_user_id has been found. I suppose I need to work with a JOIN here, but I currently can't figure out where exactly.
You are already using a correlated subquery. You can use that to get the value:
ELSE (SELECT COALESCE(MAX(bu.backend_type), 'unknown')
FROM backend_users bu
WHERE bu.id = video_calls.initiated_user_id
)
Note the use of MAX(). This ensures that exactly one value is returned. If no rows match, the MAX() returns NULL, so 'unknown' is returned.
This has one slight nuance from your pseudo-code. If the matching row is NULL, then this returns 'unknown' rather than NULL. If that is an issue, the logic in the subquery can be tweaked.
I have a table named GAINLP
The table contains fields
'Record#" (INT),
'SightingDate' (DATE),
'SpeciesName' (VARCHAR)
Need SQL to output an array that contains an integer that corresponds to the sum of SightingDate for each month.
Example: 0,0,0,0,1,5,10,12,5,3,0,0
Instead, the following code causes null value sums to be skipped and I'm left with 1,5,10,12,5,3
`select count(SightingDate) from GAINLP where SpeciesName LIKE '%Actias luna' GROUP BY MONTH(SightingDate)`
I understand that this can be done by joining with a calendar table, but I've not found examples of such code that also employs the WHERE operator.
You could use conditional aggregation here:
SELECT
MONTH(SightingDate) AS month,
COUNT(CASE WHEN SpeciesName LIKE '%Actias luna' THEN 1 END) cnt
FROM GAINLP
GROUP BY
MONTH(SightingDate);
But, this might not be as efficient as a calendar table based join approach. Here is how you might do that:
SELECT
t1.month,
COUNT(t2.SightingDate) cnt
FROM (SELECT DISTINCT MONTH(SightingDate) AS month FROM GAINLP) t1
LEFT JOIN GAINLP t2
ON t1.month = MONTH(t2.SightingDate)
WHERE
t2.SpeciesName LIKE '%Actias luna'
GROUP BY
t1.month;
Note: It might be possible that your data could span more than a given year, in which case you would probably want to report both the year and month.
You seem to be looking for conditional aggregation. The principle is to move the filtering logic to a CASE construct within the aggregate function.
SELECT
SUM(
CASE
WHEN SpeciesName LIKE '%Actias luna'
THEN 1
ELSE 0
END
)
GROM gainlp
GROUP BY MONTH(SightingDate)
I have a table containing the names, emails, positions, etc of a students, as well as their "status" (which can be one of Y or N.) I want to write a query that counts the number of each type of position, as well as the number of Y AND the number of N within each type using JOIN. (That is, it would be a table with three columns: Position, StatusIsYes, and StatusIsNo.)
I have already done this using the CASE clause the following way, but I can't figure out how to do it using the JOIN clause.
SELECT position,
COUNT(CASE WHEN status = 'Y' THEN 1 ELSE NULL END) AS StatusIsYes,
COUNT(CASE WHEN status = 'N' THEN 1 ELSE NULL END) AS StatusIsNo
FROM
students GROUP BY crd
I appreciate any suggestions!
EDIT: I know it can be done without using JOIN, but I want to know how it is possible to do it with a JOIN.
You don't need a join:
SELECT
position,
SUM(status = 'Y') AS StatusIsYes,
SUM(status = 'N') AS StatusIsNo
FROM students
GROUP BY position
Note the rather funky dispensing of the CASE, because in mysql (only) true is 1 and false is 0, so sum() of a condition counts how many times it is true :)
You can use SELF JOIN in the case when you want to fetch records from same table.
For ex:
Table Name: employee
Fields : EmpId,EmpName,ManagerId
Now if you want to get the details of Empolyees who are in Manager Position for that we need to write query like this:
SELECT e1.EmpId, e1.EmpName FROM EmployeeDetails e1, EmployeeDetails e2 where e1.EmpId=e2.ManagerId;
Hope it will help you.
Fro more information please check this link.
Try ::
SELECT
position,
COUNT(status = 'Y' ) AS StatusIsYes,
COUNT(status = 'N' ) AS StatusIsNo
FROM
students GROUP BY POSITION