sql server get several group by results from one query result - sql-server

Is it possible to to retrieve several group by results from one query?
Currently I've a freetext book-title search system which returns the top X rows:
First it queries the book-titles
SELECT TOP 16 grouped_location, grouped_author, book_title
FROM books
WHERE book_title like '%foo%'
then it queries the location group
SELECT grouped_location, COUNT(*)
FROM books
WHERE book_title like '%foo%'
GROUP BY grouped_location
then it queries the author group: ....
Is it possible to retrieve this information with one search?
I have no problem by sending multiple command to the SQL server, but the goal is that the SQL server only performs one search and not using up all resources by searching three times.
Please keep in mind that a client-side solution, by returning all records to the client and calculate the grouped results, is not an option. It requires to only return the TOP X records due to performance reasons.

This query will give you row détails, with count by grouped_location for each row.
Change the ORDER BY to meet your requirements
select top 16 grouped_location, grouped_author, book_title,
count(*) over (partition by grouped_location) as [count]
FROM books
WHERE book_title like '%foo%'
-- order by grouped_author or some other column
order by [count] desc

To see information only grouped by grouped_location, you could so something like this..
SELECT grouped_location , COUNT(*) Totals
FROM
(
SELECT TOP 16 grouped_location, grouped_author, book_title
FROM books
WHERE book_title like '%foo%'
ORDER BY Some_Column
) Q
GROUP BY grouped_location
To see information grouped by All the columns, you could so something like this..
SELECT grouped_location, grouped_author, book_title, COUNT(*) Totals
FROM
(
SELECT TOP 16 grouped_location, grouped_author, book_title
FROM books
WHERE book_title like '%foo%'
ORDER BY Some_Column
) Q
GROUP BY grouped_location, grouped_author, book_title

Related

SQL - Filter calculated column with calculated column

I'm trying to find out the most dosed patients in a database. The sum of the doses has to be calculated and then I have to dynamically list out the patients who have been dosed that much. The query has to be dynamic, and there can be more than 5 patients listed - For example, the 5 most doses are 7,6,5,4,3 doses, but 3 people have gotten 5 doses, so I'd have to list out 7 people in total (the patients getting 7,6,5,5,5,4,3 doses). I'm having issues because you cannot refer to a named column in a where clause and I have no idea how to fix this.
The query goes like this:
SELECT
info.NAME, SUM(therapy.DOSE) AS total
FROM
dbo.PATIENT_INFORMATION_TBL info
JOIN
dbo.PATIENT_THERAPY_TBL therapy ON info.HOSPITAL_NUMBER = therapy.HOSPITAL_NUMBER
LEFT JOIN
dbo.FORMULARY_CLINICAL clinical ON clinical.ITEMID = therapy.ITEMID
WHERE
total IN (SELECT DISTINCT TOP 5 SUM(t.DOSE) AS 'DOSES'
FROM dbo.PATIENT_INFORMATION_TBL i
JOIN dbo.PATIENT_THERAPY_TBL t ON i.HOSPITAL_NUMBER = t.HOSPITAL_NUMBER
LEFT JOIN dbo.FORMULARY_CLINICAL c ON c.ITEMID = t.ITEMID
GROUP BY NAME
ORDER BY 'DOSES' DESC)
GROUP BY
info.NAME
ORDER BY
total DESC
The database looks like this:
The main question is: how can I use a where/having clause where I need to compare a calculated column to a list of dynamically calculated values?
I'm using Microsoft's SQL Server 2012. The DISTINCT in the subquery is needed so that only the top 5 dosages appear (e.g. without DISTINCT I get 7,6,5,4,3 with DISTINCT I get 7,6,6,5,4 and my goal is the first one).
Most DBMSes support Standard SQL Analytical Functions like DENSE_RANK:
with cte as
(
SELECT info.NAME, SUM(therapy.DOSE) as total,
DENSE_RANK() OVER (ORDER BY SUM(therapy.DOSE) DESC) AS dr
FROM dbo.PATIENT_INFORMATION_TBL info
JOIN dbo.PATIENT_THERAPY_TBL therapy ON info.HOSPITAL_NUMBER=therapy.HOSPITAL_NUMBER
LEFT JOIN dbo.FORMULARY_CLINICAL clinical ON clinical.ITEMID=therapy.ITEMID
GROUP BY info.NAME
)
select *
from cte
where dr <= 5 -- only the five highest doses
ORDER BY total desc
Btw, you probably don't need the LEFT JOIN as you're not selecting any column from dbo.FORMULARY_CLINICAL

Append the results of subquery in oracle

Suppose I've query like below in oracle:
SELECT author_id, author_name,
(
SELECT book_title FROM books
WHERE author_id = a.author_id
)
FROM author a
Here in subquery for particular author_id can have multiple books written by them. But Oracle won't allow to return multiple rows from subquery. So how can I append the different book_title by comma seperated for same author in oracle in a row.
LISTAGG might help:
select
a.author_id,
a.author_name,
listagg(b.book_title, ',') within group (order by null) list_of_books
from author a join books b on b.author_id = a.author_id
group by a.author_id, a.author_name;

SQL Server Select statement

Each vendor in Vendors table has a pre-assigned [DefaultAccountNo].
Write a SELECT statement with GROUP BY, ORDER BY, and TOP to find five DefaultAccountNo that are assigned to the most vendors. Please include in your answer all DefaultAccountNo if they are associated with the same number of vendors that meet the condition. If any such DefaultAccountNo exists, your answer will contain six or more DefaultAccountNo.
This is what I have attempted, But I am not getting the desired output
SELECT TOP 5 with ties DefaultAccountNo, DefaultTermsID, COUNT (*) as
VendorsQty
FROM Vendors
GROUP BY DefaultAccountNo, DefaultTermsID
Having count(*) >= 5
ORDER BY DefaultAccountNo DESC
Something like this (you have use either subquery or CTE):
SELECT TOP 5 with ties
source.*
FROM
(
SELECT DefaultAccountNo, count(distinct VendorId) as VendorsCount
FROM Vendors
GROUP BY DefaultAccountNo
) as source
ORDER BY VendorsCount Desc

Select distinct records from MS SQL database when querying row numbers

This query returns 5 identical products, because there are 5 keywords associated with the resulting product:
SELECT
products.field1,
products.field2
FROM products,
keywords
WHERE products.itemnum = keywords.itemnum
AND products.itemnum = 123
ORDER BY products.field1, products.field2
If I put a "distinct" after "select", then I get 1 result, which is what I want.
However, when I setup my query like this:
SELECT
*
FROM (SELECT
ROW_NUMBER() OVER (ORDER BY products.field1, products.field2) AS rownum,
products.field1,
products.field2
FROM products,
keywords
WHERE products.itemnum = keywords.itemnum
AND products.itemnum = 123) AS qryresults
WHERE rownum >= 1
AND rownum <= 20
I get 5 identical products again. There doesn't seem to be anywhere I can put a "distinct" statement to limit it to 1 result. I'm sure the reason is that by adding the row numbers, that doesn't make the results "distinct" anymore.
I am using the technique shown in this query to limit potentially large search results to only 20 records at a time, which greatly reduces overhead and speeds up my query. So if there are 100,000 results, I can easily set this up to return records 90,000-90,020, for example.
MySQL has this kind of thing built-in, but with MS SQL this is the workaround.
However, I am having trouble figuring out how to make it work when I am combining the keywords table.
If I replace the * with a list of columns, then I get an error:
The multi-part identifier could not be bound.
I'm not sure what else to try. Is there a way to correct this?
Thank you.
Use a CTE to separate the distinct and the ROW_NUMBER() function:
with cte as (select distinct products.field1
, products.field2
from products, keywords
where products.itemnum=keywords.itemnum and products.itemnum=123),
row_n as (select field1
, field2
, row_number() over (order by field1, field2) as rownum
from cte)
select field1, field2
from row_n
where rownum>=1 and rownum<=20

Duplicate values and group by throwing query results off

I'm trying to execute a query and having some issues. The objective is to find all duplicate values for a specific field (Upc) that manufacturers (idPub) are using. An example is manufacturer A uses upc 1010 while manufacture B also occupies upc 1010. This data is stored in one table. So far, I've come up with this query below...
USE dbIdwWhseLC
SELECT tbItem.sUpc, COUNT(*) AS NumberofDups
FROM tbItem
WHERE sUpc IS NOT NULL
GROUP BY sUpc
HAVING COUNT(*) > 1
ORDER BY COUNT(*)
The query is displaying the correct data as far as upc numbers and counts, however when attempting to throw the manufacturer field in the query, I have to group by that manufacturer field too which is throwing the results off. I'm trying to the query to return data like this below...
Upc idPub
1010 A
1010 B
Any recommendations would be greatly appreciated. Thanks.
You have to join back to your main table, like so:
WITH Duplicates AS
(
Select tbItem.sUpc
,COUNT(*) As NumberofDups
From tbItem
Where sUpc is not null
Group by sUpc
Having COUNT(*)>1
)
SELECT
D.sUpc
,TI.idPub
,M.[name]
FROM
Duplicates AS D
INNER JOIN
tblItem AS TI
ON
D.sUpc = TI.sUpc
INNER JOIN
tbMfrReporting AS M
ON
TI.nIdPub = M.nIdPub
The Duplicates statement above is known as a CTE.
I hope that helps.
Ash
EDIT: query updated to add further table as per comments
You want to find all the entries where the upc is in the list of UPCs that have more than one entry, so...
select sUpc, idPub
from tbItem
where sUpc in
(
Select tbItem.sUpc
From tbItem
Where sUpc is not null
Group by sUpc
Having COUNT(*)>1
)

Resources