SQL Select Entire Row by Distinct Columns - sql

I need an sql statement which will allow me to select an entire row from oracle database, but by distinct columns. Here is a simplified database:
Project_Num Title Category
0 Project 1 Admin
0 Project 1 Development
1 Project 2 Admin
2 Project 3 Development
I need my statement to return the following result set:
0 Project 1 Admin
1 Project 2 Admin
2 Project 3 Development
So each project is returned based on whether its project_num and title are unique. If a project has 2+ entries where its category is different, I need to only select that project once (it doesn't matter which entry I select for that project).
Can anyone help me please?

SELECT Project_Num, Title, MIN(Category) AS Category
FROM MyTable
GROUP BY Project_Num, Title;

Do you even need to have the Category column in your result set?
If not then you could just use:
SELECT DISTINCT Project_Num, Title
FROM MyTable

SELECT *
FROM (SELECT DISTINCT YourDistinctField FROM YourTable) AS A
CROSS APPLY
( SELECT TOP 1 * FROM YourTable B
WHERE B.YourDistinctField = A.YourDistinctField ) AS NewTableName
I have been trying to figure this out for hours now, I tried lots of solutions that didn't work and finally got it by searching for "joining top 1" and adapting that solution I found to a distinct search.

Related

TypeORM & Postgres: Count only unique distinct values from multiple columns

I have various SQL queries, which return me unique / distinct value from DB, (or count them),
like:
SELECT buyer as counterparty
FROM public.order
UNION
SELECT seller as counterparty
FROM public.order
or
SELECT COUNT(*)
FROM (
SELECT DISTINCT p
FROM public.order
CROSS JOIN LATERAL (VALUES(seller),(buyer)) AS C(p)
) AS internalQuery
Example structure of my table:
id buyer seller
0 A B
1 B A
2 B D
3 D A
4 A D
Desired result:
3 or A,B,D
I'd like to rewrite them with TypORM query builder, but I can't figure out, how to replace CROSS JOIN LATERAL (VALUES(seller),(buyer)) AS C(p) or UNION in my case. TypeORM is pretty poor with examples and doc coverage in this case.
Does there any option with that?
I have seen various methods like .getCount and .distinct(true) which could help me and easily find the solution for one column.
So I understood, that if I want to find the exact number, instead of doc results, I should use .getCount instead of .getMany
But I can't understand, how to select (and unite) values from multiple columns via typeORM to receive distinct values from multiple columns.
I am working with PostgrSQL, so when I am trying:
const query = repository.createQueryBuilder('order')
.distinctOn(['buyer', 'seller'])
.limit(100)
.getMany()
I receive docs with each distinct value in each field, so instead of 3 I get 6 values (3 distinct by column1, and 3 by column2)

Annotating rows if backwards relationship exists (Postgres)

So I have 3 tables: Recommendation, Article and User.
Recommendation has 4 columns:
id | integer
article_id |integer
user_id |integer
submit_time |integer
Article has 3 columns:
id | integer
title
url
I need to obtain a list of all articles, while also annotating each row with a new recommended column, which is 1 if the user in question has recommended the article or 0 if not. There shouldn't be any duplicate Article in the result, and I need it ordered by the Recommendation's submit_time column.
This is on Postgres - 9.1.8.
SELECT DISTINCT ON(t.title) t.title,
t.id, t.url,
MAX(recommended) as recommended
FROM (
SELECT submitter_article.title as title,
submitter_article.id as id,
submitter_article.url as url,
1 as recommended
FROM submitter_article, submitter_recommendation
WHERE submitter_recommendation.user_id=?
AND submitter_recommendation.article_id=submitter_article.id
UNION ALL
SELECT submitter_article.title as title,
submitter_article.id as id,
submitter_article.url as url,
0 as recommended
FROM submitter_article
) as t
GROUP BY t.title, t.id, t.url, recommended
And I'm passing a user id into the ?
I've been trying to do this for a while but can't figure it out. The queries I come up with either return all recommended values as 0, or return duplicate Article rows (one with recommended=0 and the other with recommended=1).
Any ideas?
You don't need a subquery, CASE will do, DISTINCT ON is useless if you also use GROUP BY and you should use explicit joins instead of implicit joins. This query should get you started:
SELECT DISTINCT ON (sa.title) sa.title, sa.id, sa.url,
(CASE
WHEN sr.id IS NULL THEN 0
ELSE 1
END) AS recommended
FROM submitter_article AS sa
LEFT JOIN submitter_recommendation AS sr ON sa.id=sr.article_id
AND sr.user_id=?
ORDER BY sa.title,sr.submit_time DESC;
But there are still some things I'm not sure. You can have two articles with the same title but diffrent id? In that case you can select that which has earlier/later recommendation submit_time but what if there are no recommendations? You need logic for how to select distinct rows and for how to order things in the end.

Can I write this query using the criteria API or am I stuck with HQL?

I have the following query which I would like to write using the criteria api of NH.
select status, count(1) from (select distinct Status, post_id from post_statistics) tbl group by status
each post_id can exist multiple times in post_statistics
e.g.
id post_id status
1 1 open
1 1 edit
1 1 open
1 2 open
so the query should return the following results:
status count
open 2
edit 1
thx in advance.
mappings, classes?
if i'm thinking right, with a proper mapping this would effectively be something like
(pseudo-HQL)
select stat.Name, count(stat.Posts) from status stat

SQL Order By list of strings?

I wish to do a select on a table and order the results by a certain keyword or list of keywords. For example I have a table like so:
ID Code
1 Health
2 Freeze
3 Phone
4 Phone
5 Health
6 Hot
so rather than just do a simple Order By asc/desc I'd like to order by Health, Phone, Freeze, Hot. Is this possible?
Try using this:
select * from table
order by FIELD(Code, 'Health', 'Phone', 'Freeze', 'Hot')
Here's a horrible hack:
select * from table
order by (
case Code
when 'Health' then 0
when 'Phone' then 1
when 'Freeze' then 2
when 'Hot' then 3
end
)
You can join with the Keywords table, and include a sequence column, and ORDER BY Keyword.Sequence.
Example your keywords table looks like this:
ID Code Sequence
1 Health 1
2 Freeze 3
3 Phone 2
4 Hot 4
Then you can join.
SELECT *
FROM MyTable INNER JOIN
Keywords ON Keywords.ID = MyTable.KeywordID
ORDER BY Keywords.Sequence
Hope this gives you the idea.
Nowadays MySQL has a function called find_in_set()
Use it like this:
select * from table
order by find_in_set(Code,'Health','Phone','Freeze','Hot')
Is this just a one off ORDER BY or something that you're going to want to do often and on more values than specified here?
The order that you have given is arbitrary, therefore an identifier needs to be given to achieve what you want
SELECT
ID,
Code,
CASE Code
WHEN 'Health' THEN 1
WHEN 'Phone' THEN 2
WHEN 'Freeze' THEN 3
WHEN 'Hot' THEN 4
END As OrderBy
FROM Table
ORDER BY
OrderBy
Or
SELECT
ID,
Code
FROM Table
ORDER BY
CASE Code
WHEN 'Health' THEN 1
WHEN 'Phone' THEN 2
WHEN 'Freeze' THEN 3
WHEN 'Hot' THEN 4
END
(I'm not familiar with MySQL but the above would work in SQL Server. The syntax for MySQL won't be too different)
If you're likely to want to do this often, then create an OrderBy column on the table or create an OrderBy table with a FK link to this table and specify an OrderBy numerical field in that.
Hi this is a SQL Server query but I am sure you can do this in MySQL as well:
SELECT ID, Code
FROM x
ORDER BY
CASE Code WHEN 'Health' THEN 1
WHEN 'Phone' THEN 2
WHEN 'Freeze' THEN 4
WHEN 'Hot' THEN 5
ELSE 6 END ASC
, Code ASC
Couple options:
Add OrderCode column with numerical
desired order
Add a table with FK to this table ID
and OrderCode
Yes join your results to your code table and then order by code.CodeOrder
EDIT: Explaing the use of the code table...
Create a separate table of Codes (CodeId, Code, CodeOrder) and join to this and order by CodeOrder. This is nicer than doing the order by (case...) hack suggested since you can easily change the codes and the orders.

Reporting against a CSV field in a SQL server 2005 DB

Ok so I am writing a report against a third party database which is in sql server 2005. For the most part its normalized except for one field in one table. They have a table of users (which includes groups.) This table has a UserID field (PK), a IsGroup field (bit) , a members field (text) this members field has a comma separated list of all the members of this group or (if not a group) a comma separated list of the groups this member belongs to.
The question is what is the best way to write a stored procedure that displays what users are in what groups? I have a function that parses out the ids into a table. So the best way I could come up with was to create a cursor that cycles through each group and parse out the userid, write them to a temp table (with the group id) and then select out from the temp table?
UserTable
Example:
ID|IsGroup|Name|Members
1|True|Admin|3
2|True|Power|3,4
3|False|Bob|1,3
4|False|Susan|2
5|True|Normal|6
6|False|Bill|5
I want my query to show:
GroupID|UserID
1|3
2|3
2|4
5|6
Hope that makes sense...
If you have (or could create) a separate table containing the groups you could join it with the users table and match them with the charindex function with comma padding of your data on both sides. I would test the performance of this method with some fairly extreme workloads before deploying. However, it does have the advantage of being self-contained and simple. Note that changing the example to use a cross-join with a where clause produces the exact same execution plan as this one.
Example with data:
SELECT *
FROM (SELECT 1 AS ID,
'1,2,3' AS MEMBERS
UNION
SELECT 2,
'2'
UNION
SELECT 3,
'3,1'
UNION
SELECT 4,
'2,1') USERS
LEFT JOIN (SELECT '1' AS MEMBER
UNION
SELECT '2'
UNION
SELECT '3'
UNION
SELECT '4') GROUPS
ON CHARINDEX(',' + GROUPS.MEMBER + ',',',' + USERS.MEMBERS + ',') > 0
Results:
id members group
1 1,2,3 1
1 1,2,3 2
1 1,2,3 3
2 2 2
3 3,1 1
3 3,1 3
4 2,1 1
4 2,1 2
Your technique will probably be the best method.