I use SQL Server 2008, C#, I have a table which contains about 20000 rows, I have several similar rows in this table, there are about 900 distinct rows, it is my table structure:
tblCourse
courselevel, coursecode, coursename, branchcode...
For example I have 20 rows with the same coursecode/coursename but with different branchcode or courselevel, I'm going to have a table which contains item with only unique coursecode.
here is a little sample of my table:
... courselevel=1,coursecode=1200,coursename=A,branchcode=200...
... courselevel=2,coursecode=1200,coursename=A,branchcode=200...
... courselevel=1,coursecode=1200,coursename=A,branchcode=220...
... courselevel=1,coursecode=1200,coursename=A,branchcode=230...
... courselevel=1,coursecode=1200,coursename=A,branchcode=240...
... courselevel=1,coursecode=1200,coursename=A,branchcode=250...
... courselevel=2,coursecode=1200,coursename=A,branchcode=251...
... courselevel=1,coursecode=1200,coursename=A,branchcode=225...
I want to have only the first row:
... courselevel=1,coursecode=1200,coursename=A,branchcode=200...
because all rows have similar coursecode,
What should I do?
How should I write my select query string?
I have tested different methods (group by, distinct, max(ID)...) with no luck, please help me!
thanks
You can GROUP BY the similar columns and use any Aggregate Function on the other columns to have them just return one record. What that one value would be entirely depends on the aggregate function you use.
Aggregate Functions
Aggregate functions perform a calculation on a set of values and
return a single value. Except for COUNT, aggregate functions ignore
null values. Aggregate functions are frequently used with the GROUP BY
clause of the SELECT statement
In this example, I have used the min/max and avg aggregate functions.
SELECT courselevel
, coursecode
, coursename
, MIN(branchcode)
, MAX(othercolumn)
, AVG(numberColumn)
, ...
FROM yourTable
GROUP BY
courselevel
, coursecode
, coursename
Related
I have a table that I need to add the same values to a whole bunch of items
(in a nut shell if the item doesn't have a UNIT of "CTN" I want to add the same values i have listed to them all)
I thought the following would work but it doesn't :(
Any idea what i am doing wrong ?
INSERT INTO ICUNIT
(UNIT,AUDTDATE,AUDTTIME,AUDTUSER,AUDTORG,CONVERSION)
VALUES ('CTN','20220509','22513927','ADMIN','AU','1')
WHERE ITEMNO In '0','etc','etc','etc'
If I understand correctly you might want to use INSERT INTO ... SELECT from original table with your condition.
INSERT INTO ICUNIT (UNIT,AUDTDATE,AUDTTIME,AUDTUSER,AUDTORG,CONVERSION)
SELECT 'CTN','20220509','22513927','ADMIN','AU','1'
FROM ICUNIT
WHERE ITEMNO In ('0','etc','etc','etc')
The query you needs starts by selecting the filtered items. So it seems something like below is your starting point
select <?> from dbo.ICUNIT as icu where icu.UNIT <> 'CTN' order by ...;
Notice the use of schema name, terminators, and table aliases - all best practices. I will guess that a given "item" can have multiple rows in this table so long as ICUNIT is unique within ITEMNO. Correct? If so, the above query won't work. So let's try slightly more complicated filtering.
select distinct icu.ITEMNO
from dbo.ICUNIT as icu
where not exists (select * from dbo.ICUNIT as ctns
where ctns.ITEMNO = icu.ITEMNO -- correlating the subquery
and ctns.UNIT = 'CTN')
order by ...;
There are other ways to do that above but that is one common way. That query will produce a resultset of all ITEMNO values in your table that do not already have a row where UNIT is "CTN". If you need to filter that for specific ITEMNO values you simply adjust the WHERE clause. If that works correctly, you can use that with your insert statement to then insert the desired rows.
insert into dbo.ICUNIT (...)
select distinct icu.ITEMNO, 'CTN', '20220509', '22513927', 'ADMIN', 'AU', '1'
from ...
;
I have a table like below:
How can I have a column like below using Transact-SQL (Order By Date)?
I'm using SQL Server 2016.
The thing you need is called an aggregate windowing function, specifically SUM ... OVER.
The problem is that a 'running total' like this only makes sense if you can specify the order of the rows deterministically. The sample data does not include an attribute that could be used to provide this required ordering. Tables, by themselves, do not have an explicit order.
If you have something like an entry date column, a solution like the following would work:
DECLARE #T table
(
EntryDate datetime2(0) NOT NULL,
Purchase money NULL,
Sale money NULL
);
INSERT #T
(EntryDate, Purchase, Sale)
VALUES
('20180801 13:00:00', $1000, NULL),
('20180801 14:00:00', NULL, $400),
('20180801 15:00:00', NULL, $400),
('20180801 16:00:00', $5000, NULL);
SELECT
T.Purchase,
T.Sale,
Remaining =
SUM(ISNULL(T.Purchase, $0) - ISNULL(T.Sale, 0)) OVER (
ORDER BY T.EntryDate
ROWS UNBOUNDED PRECEDING)
FROM #T AS T;
Demo: db<>fiddle
Using ROWS UNBOUNDED PRECEDING in the window frame is shorthand for ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW. The behaviour of ROWS is different w.r.t duplicates (and generally better-performing) than the default RANGE. There are strong arguments to say that ROWS ought to have been the default, but that is not what we were given 🙂.
For more information see How to Use Microsoft SQL Server 2012's Window Functions by Itzik Ben-Gan, and his excellent book on the topic.
Okay it has been quite some time since I have used SQL Server very intensively for writing queries.
There has to be some gotcha that I am missing.
As per my understanding the following two queries should return the same number of duplicate records
SELECT COUNT(INVNO)
, INVNO
FROM INVOICE
GROUP BY INVNO
HAVING COUNT(INVNO) > 1
ORDER BY INVNO
SELECT DISTINCT invno
FROM INVOICE
ORDER BY INVNO
There are no null values in INVNO
Where could I be possible going wrong?
Those queries will not return same results. First one will only give you INVNO values that have duplicates, second will give all unique INVNO values, even if they appear only once in entire table.
the group by query will filter our all the single invoices while the distinct will simply pick one from every invoice. First query is a subset of the second
In addition to what Adam said, the GROUP BY will sort the data on the GROUPed columns.
I have this table:
What I want to do is aggregate these so each instructor has one line, so I used this SQL:
Select
TermCode, SubjectCode, course, QuestionNbr, InstructorName,
Sum(TotalStudents) as TotalStudents, Avg(Mean) as Mean,
StDev(StdDev) as StdDev
From
#MyTable
Group By
TermCode, SubjectCode, course, QuestionNbr, InstructorName
And I get this:
The problem is that any instructor with just one entry will have a null StdDev, which is to be expected. What I want is in those cases to use the StdDev value from the original table, so I would get this:
Is there a way to do this?
One approach would be to use COALESCE with an aggregate function that won't return NULL - such as Max:
COALESCE(StDev(StdDev),Max(StdDev)) as StdDev
I am working on an SQL query which should group by a column bidBroker and return all the columns in the table.
I tried it using the following query
select Product,
Term,
BidBroker,
BidVolume,
BidCP,
Bid,
Offer,
OfferCP,
OfferVolume,
OfferBroker,
ProductID,
TermID
from canadiancrudes
group by BidBroker
The above query threw me an error as follows
Column 'canadiancrudes.Product' is invalid in the select list because it is not contained in either an aggregate function or the
GROUP BY clause.
Is there any other way which returns all the data grouping by bidBroker without changing the order of data coming from CanadadianCrudes?
First if you are going to agregate, you should learn about agregate functions.
Then grouping becomes much more obvious.
I think you should explain what you are trying to accomplish here, because I suspect that you are trying to SORT bu Bidbroker, rather than grouping.
If you mean you want to sort by BidBroker, you can use:
SELECT Product,Term,BidBroker,BidVolume,BidCP,Bid,Offer,OfferCP,OfferVolume,OfferBroker,ProductID,TermID
FROM canadiancrudes
ORDER BY BidBroker
If you want to GROUP BY, and give example-data you can use:
SELECT c1.Product,c1.Term,c1.BidBroker,c1.BidVolume,c1.BidCP,c1.Bid,c1.Offer,c1.OfferCP,c1.OfferVolume,c1.OfferBroker,c1.ProductID,c1.TermID
FROM canadiancrudes c1
WHERE c1.YOURPRIMARYKEY IN (
select MIN(c2.YOURPRIMARYKEY) from canadiancrudes c2 group by c2.BidBroker
)
Replace YOURPRIMARYKEY with your column with your row-unique id.
As others have said, don't use "group by" if you don't want to aggregate something. If you do want to aggregate by one column but include others as well, consider researching "partition."