SQL simple GROUP BY query - sql

Is there a way to make a simple GROUP BY query with SQL and not use COUNT,AVG or SUM? I want to show all columns and group it with a single column.
SELECT * FROM [SPC].[dbo].[BoardSFC] GROUP BY boardsn
The query above is working on Mysql but not on SQL, is there a way to achieve this? any suggestion would be great
UPDATE: Here is my data I just need to group them by boardsn and get imulti equals to 1

I thing you just understand 'group data' in a different way than it is implemented in sql server. You simply want rows that have the same value together in the result and that would be ordering not grouping. So maybe what you need is:
SELECT *
FROM [SPC].[dbo].[BoardSFC]
WHERE imulti = 1
ORDER BY boardsn

The query above is working on Mysql but not on SQL, is there a way to achieve this? any suggestion would be great
No, there is not. MySQL only lets you do this because it violates the various SQL standards quite egregiously.
You need to name each column you want in the result-set whenever you use GROUP BY. The SELECT * feature is only provided as a convenience when working with data interactively - in production code you should never use SELECT *.

You could use a TOP 1 WITH TIES combined with a ORDER BY ROW_NUMBER.
SELECT TOP 1 WITH TIES *
FROM [SPC].[dbo].[BoardSFC]
ORDER BY ROW_NUMBER() OVER (PARTITION BY boardsn ORDER BY imulti)
Or more explicitly, use ROW_NUMBER in a sub-query
SELECT *
FROM
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY boardsn ORDER BY imulti) as RN
FROM [SPC].[dbo].[BoardSFC]
) q
where RN = 1

Related

Jet-SQL to TSQL

In MS Access 2010 I have the following code:
SELECT
[Teile-LF-Beziehungen].Lieferant,
COUNT([Teile-LF-Beziehungen].Lieferant) AS [Anz Teile],
First([Teile-LF-Beziehungen].Name) AS Name
FROM
[Teile-LF-Beziehungen]
GROUP BY
[Teile-LF-Beziehungen].Lieferant
ORDER BY
COUNT([Teile-LF-Beziehungen].Lieferant) DESC;
I want to put that query into SQL Server, because MS Access should be only the frontend.
But in SQL Server I can't use the ORDER in a view. But why? I don't understand it. The code I want to use in SQL Server:
SELECT
[Lieferant],
COUNT([Lieferant]) AS [Anz Teile],
MIN([Name]) AS [Name]
FROM
[dbo].[VIEW_Teile-LF-Beziehungen]
GROUP BY
[Lieferant]
ORDER BY
COUNT([Lieferant]) DESC;
I know it don't work. But is there any way to incur a MS Access query 1:1 to a SQL Server query (view)?
Only the outermost select can use an order by (but you might state a TOP 100 percent to trick this out). Therefore it is perfectly OK, that at VIEW does not allow this.
Many people think, that tables have kind of an implicit order (as you see the result ordered), but this is random... The next call could lead to a different sorting.
There is another way using ROW_NUMBER with OVER(ORDER BY). The result is delivered in this order and the order is guaranteed as long the orderby is sorting after unique values.
EDIT
Sorry my first attempt was to quick. The ROW_NUMBER was not allowed due to the grouping
This should work:
SELECT tbl.Lieferant
,tbl.[Anz Teile]
,tbl.Name
,ROW_NUMBER() OVER(ORDER BY tbl.[Anz Teile] DESC) AS Sort
FROM
(
SELECT [Lieferant]
,COUNT([Lieferant]) AS [Anz Teile]
,MIN([Name]) AS [Name]
FROM [dbo].[VIEW_Teile-LF-Beziehungen]
GROUP BY [Lieferant]
) AS tbl;
EDIT2
This SELECT can be placed within a VIEW, just place your CREATE VIEW YourViewName AS before the SELECT and execute. After this you'll be able to do a SELECT * FROM YourViewName to get a sorted list.
BUT
As stated in many places: The best is the outermost ORDER BY in any case!
ORDER BY doesnt work inside the view. SQL server is free to return the rows anyway he want if you dont include the order by when calling the View
So you need
SELECT *
FROM yourView
ORDER BY yourField
EDIT: Im saying if your view is
CREATE VIEW yourView AS
SELECT
[Lieferant],
COUNT([Lieferant]) AS [Anz Teile],
MIN([Name]) AS [Name]
FROM
[dbo].[VIEW_Teile-LF-Beziehungen]
GROUP BY
[Lieferant];
Then you call your View like this
SELECT *
FROM yourView
ORDER BY [Anz Teile]

Why do partitions require nested selects?

I have a page to show 10 messages by each user (don't ask me why)
I have the following code:
SELECT *, row_number() over(partition by user_id) as row_num
FROM "posts"
WHERE row_num <= 10
It doesn't work.
When I do this:
SELECT *
FROM (
SELECT *, row_number() over(partition by user_id) as row_num FROM "posts") as T
WHERE row_num <= 10
It does work.
Why do I need nested query to see row_num column? Btw, in first request I actually see it in results but can't use where keyword for this column.
It seems to be the same "rule" as any query, column aliases aren't visible to the WHERE clause;
This will also fail;
SELECT id AS newid
FROM test
WHERE newid=1; -- must use "id" in WHERE clause
SQL Query like:
SELECT *
FROM table
WHERE <condition>
will execute in next order:
3.SELECT *
1.FROM table
2.WHERE <condition>
so, as Joachim Isaksson say, columns in SELECt clause are not visible in WHERE clause, because of processing order.
In your second query, column row_num are fetched in FROM clause first, so it will be visible in WHERE clause.
Here is simple list of steps in order they executes.
There is a good reason for this rule in standard SQL.
Consider the statement:
SELECT *, row_number() over (partition by user_id) as row_num
FROM "posts"
WHERE row_num <= 10 and p.type = 'xxx';
When does the p.type = 'xxx' get evaluated relative to the row number? In other words, would this return the first ten rows of "xxx"? Or would it return the "xxx"s in the first ten rows?
The designers of the SQL language recognize that this is a hard problem to resolve. Only allowing them in the select clause resolves the issue.
You can check this topic and this one on dba.stockexchange.com about order in which SQL executes SELECT clause. I think it aplies not only for PostgreSQL, but for all RDBMS.

SQL random aggregate

Say I have a simple table with 3 fields: 'place', 'user' and 'bytes'. Let's say, that under some filter, I want to group by 'place', and for each 'place', to sum all the bytes for that place, and randomly select a user for that place (uniformly from all the users that fit the 'where' filter and the relevant 'place'). If there was a "select randomly from" aggregate function, I would do:
SELECT place, SUM(bytes), SELECT_AT_RANDOM(user) WHERE .... GROUP BY place;
...but I couldn't find such an aggregate function. Am I missing something? What could be a good way to achieve this?
If your RDBMS supports analytical functions.
WITH T
AS (SELECT place,
Sum(bytes) OVER (PARTITION BY place) AS Sum_bytes,
user,
Row_number() OVER (PARTITION BY place ORDER BY random_function()) AS RN
FROM YourTable
WHERE .... )
SELECT place,
Sum_bytes,
user
FROM T
WHERE RN = 1;
For SQL Server Crypt_gen_random(4) or NEWID() would be examples of something that could be substituted in for random_function()
I think your question is DBMS specific. If your DBMS is MySql, you can use a solution like this:
SELECT place_rand.place, SUM(place_rand.bytes), place_rand.user as random_user
FROM
(SELECT place, bytes, user
FROM place
WHERE ...
ORDER BY rand()) place_rand
GROUP BY
place_rand.place;
The subquery orders records in random order. The outer query groups by place, sums bytes, and returns first random user, since user is not in an aggregate function and neither in the group by clause.
With a custom aggregate function, you could write expressions as simple as:
SELECT place, SUM(bytes), SELECT_AT_RANDOM(user) WHERE .... GROUP BY place;
SELECT_AT_RAMDOM would be the custom aggregate function.
Here is precisely an implementation in PostgreSQL.
I would do a bit of a variation on Martin's solution:
select place, sum(bytes), max(case when seqnum = 1 then user end) as random_user
from (select place, bytes,
row_number() over (partition by place order by newid()) as sequm
from t
) t
group by place
(Where newid() is just one way to get a random number, depending on the database.)
For some reason, I prefer this approach, because it still has the aggregation function in the outer query. If you are summarizing a bunch of fields, then this seems cleaner to me.

Oracle 11g and SQL TOP query

While using SELECT TOP 5 * FROM SOMETABLE gives me an error
ORA-00923: FROM keyword not found where expected
I am using Oracle 11g . I am aware of using rownum for doing the same thing but just wondering SQL TOP usage is not at all supported in Oracle ? Anything need to do extra to make SQL TOP working in Oracle ??
Oracle does not support TOP. Use ROWNUM
SELECT * FROM your_table
WHERE ROWNUM <= 5
SQLFiddle example
No, Oracle does not support TOP.
As you point out, the best approach is to use rownum. Another option is the analytical function ROW_NUMBER.
The rownum keyword, while it gets you the said no. of records, does so only after applying the order by clause if you have one.
So if the SQL server query is as below, it will give you 10 most recently created records.
Select TOP 10 * from mytable order by created_date desc
But to fit Oracle, when you write this, it gets you the 10 records (that may not be the most recent ones) and arranges them in descending order, which is not what you wanted.
Select * from mytable where rownum < 10 order by created_date desc
So writing with an additional select like this would help:
SELECT * FROM (Select * from mytable order by created_date desc) where rownum < 10
SQL TOP does NOT work for Oracle.

Oracle: Display row number with 'order by' clause

I wonder how could i print a row number for sql statement where is using order.
Currently i tried ROWNUM but as i understand it works only for unsorted result set.
SELECT rownum, a.lg_id, a.full_name, a.sort_order
FROM activity_type_lang a
where a.lg_id = 'en'
order by a.full_name;
TIA
In addition to nesting the query, you can use an analytic function
SELECT row_number() OVER (ORDER BY a.full_name),
lg_id,
full_name,
sort_order
FROM activity_type_lang a
WHERE a.lg_id = 'en'
ORDER BY a.full_name
Using analytic functions also makes it easier if you want to change how ties are handled. You can replace ROW_NUMBER with RANK or DENSE_RANK.
Oh. Seems i've found already a solution.
Select rownum, lg_id, full_name, sort_order from
(SELECT a.lg_id, a.full_name, a.sort_order
FROM activity_type_lang a
where a.lg_id = 'en'
order by a.full_name);
rownum is applied before ordering, so you have to rewrite your query like this:
select rownum, xxx.* from (
SELECT a.lg_id, a.full_name, a.sort_order
FROM activity_type_lang a
where a.lg_id = 'en'
order by a.full_name
) xxx;
Hello. I wonder how could i print a
row number for sql statement where is
using order. Currently i tried ROWNUM
but as i understand it works only for
unsorted result set.
To be clear (somebody might get it wrong). It does work (but not in the way you expect). The problem with it is that it "attaches" the ROWNUM before the sort and you get your records but not in consecutive ROWNUM records. Why? Because
The first record that meets the where
criteria in a select statement is
given rownum=1
This is really good example how select / order mechanism works.