Need assistance with T-SQL query - sql

I have the following table...
orderID | itemID
---------------------
100 3425
100 3432
102 4443
102 8754
102 3425
103 6511
103 1176
103 3584
107 4967
109 0067
Now I want the queries for the following...
return the number of itemIDs for each orderID, but only for those OrderIDs with 3 or more orders per orderID
Using a single query, find all the orderIDs that have itemID 3425 and list all the itemIDs for these orderIDs.
For the first one I tried...
SELECT orderid,COUNT(itemid) AS item_count
FROM orderitems
WHERE (select COUNT(orderid) from orderitems) >2
GROUP BY orderid.
But it's not giving the desired result....I am new to T-SQL please help...

Combined Query for 1 AND 2.
SELECT OrderID
FROM tableName
GROUP BY OrderID
HAVING COUNT(*) >= 3 AND
SUM(CASE WHEN ItemID = 3425 THEN 1 ELSE 0 END) >= 1
SQLFiddle Demo
UPDATE 1
If those two problems are different,
For Problem 1
SELECT OrderID
FROM tableName
GROUP BY OrderID
HAVING COUNT(*) >= 3
SQLFiddle Demo
For Problem 2
SELECT a.*
FROM tableName a
INNER JOIN
(
SELECT OrderID
FROM tableName
GROUP BY OrderID
HAVING SUM(CASE WHEN ItemID = 3425 THEN 1 ELSE 0 END) >= 1
) b ON a.OrderID = b.OrderID
SQLFiddle Demo

Related

Partition Over issue in SQL

I have a Order shipment table like below -
Order_ID
shipment_id
pkg_weight
1
101
5
1
101
5
1
101
5
1
102
3
1
102
3
I want the output table to look like below -
Order_ID
Distinct_shipment_id
total_pkg_weight
1
2
8
select
order_id
, count(distinct(shipment_id)
, avg(pkg_weight) over (partition by shipment_id)
from table1
group by order_id
but getting the below error -
column "pkg_weight" must appear in the GROUP BY clause or be used in
an aggregate function
Please help
Use a distinct select first, then aggregate:
SELECT Order_ID,
COUNT(DISTINCT shipment_id) AS Distinct_shipment_id,
SUM(pkg_weight) AS total_pkg_weight
FROM
(
SELECT DISTINCT Order_ID, shipment_id, pkg_weight
FROM table1
) t
GROUP BY Order_ID;

SQL Select Distinct Records From Two Tables

I am trying to write a SQL statement that will return a set of Distinct set of CompanyNames from a table based on the most recent SaleDate withing a specified date range from another table.
T01 = Account
T02 = TransHeader
The fields of importance are:
T01.ID, T01.CompanyName
T02.AccountID, T02.SaleDate
T01.ID = T02.AccountID
What I want to return is the Max SaleDate for each CompanyName without any duplicate CompanyNames and only the Max(SaleDate) as LastSale. I will be using a Where Clause to limit the SaleDate range.
I tried the following but it returns all the records for all SalesDates in the range. This results in the same company being listed multiple times.
Current MS-SQL Query
SELECT T01.CompanyName, T02.LastSale
FROM
(SELECT DISTINCT ID, IsActive, ClassTypeID, CompanyName FROM Account) T01
FULL OUTER JOIN
(SELECT DISTINCT AccountID, TransactionType, MAX(SaleDate) LastSale FROM TransHeader group by AccountID, TransactionType, SaleDate) T02
ON T01.ID = T02.AccountID
WHERE ( ( T01.IsActive = 1 )AND
( (Select Max(SaleDate)From TransHeader Where AccountID = T01.ID AND TransactionType in (1,6) AND SaleDate is NOT NULL)
BETWEEN '01/01/2016' AND '12/31/2018 23:59:00' AND (Select Max(SaleDate)From TransHeader Where AccountID = T01.ID AND TransactionType in (1,6) AND SaleDate is NOT NULL) IS NOT NULL
)
)
ORDER BY T01.CompanyName
I thought the FULL OUTER JOIN was the ticket but it did not work and I am stuck.
Sample data Account Table (T01)
ID CompanyName IsActive ClassTypeID
1 ABC123 1 1
2 CDE456 1 1
3 EFG789 1 1
4 Test123 0 1
5 Test456 1 1
6 Test789 0 1
Sample data Transheader table (T02)
AccountID TransactionType SaleDate
1 1 02/03/2012
2 1 03/04/2013
3 1 04/05/2014
4 1 05/06/2014
5 1 06/07/2014
6 1 07/08/2015
1 1 08/09/2016
1 1 01/15/2016
2 1 03/20/2017
2 1 03/21/2017
3 1 03/04/2017
3 1 04/05/2018
3 1 05/27/2018
4 1 06/01/2018
5 1 07/08/2018
5 1 08/01/2018
5 1 10/11/2018
6 1 11/30/2018
Desired Results
CompanyName LastSale (Notes note returned in the result)
ABC123 01/15/2016 (Max(SaleDate) LastSale for ID=1)
CDE456 03/21/2017 (Max(SaleDate) LastSale for ID=2)
EFG789 05/27/2018 (Max(SaleDate) LastSale for ID=3)
Testing456 10/11/2018 (Max(SaleDate) LastSale for ID=5)
ID=4 & ID=6 are note returned because IsActive = 0 for these records.
One option is to select the maximum date in the select clause.
select
a.*,
(
select max(th.saledate)
from transheader th
where th.accountid = a.id
and th.saledate >= '2016-01-01'
and th.saledate < '2019-01-01'
) as max_date
from account a
where a.isactive = 1
order by a.id;
If you only want to show transaction headers with sales dates in the given date range, then you can just inner join the maximum dates with the accounts. In order to do so, you must group your date aggregation per account:
select a.*, th.max_date
from account a
join
(
select accountid, max(saledate) as max_date
from transheader
and saledate >= '2016-01-01'
and saledate < '2019-01-01'
group by accountid
) th on th.accountid = a.id
where a.isactive = 1
order by a.id;
select CompanyName,MAX(SaleDate) SaleDate from Account a
inner join Transheader b on a.id = b.accountid
group by CompanyName
order by 1

Query to return data where Id Column is unique but display number is the same?

I have data in a table like below:
CustomerId OrderId NoToDisplay
123 176 1
123 177 1
124 125 1
124 126 2
124 127 3
125 182 6
125 183 6
I am trying to write a query that returns unique order numbers that have got the same NoToDisplay Value. So from the dataset snippet above the output would be:
CustomerId OrderId NoToDisplay
123 176 1
123 177 1
125 182 6
125 183 6
This is the query I have tried but it isn't returning what I expected:
SELECT DISTINCT c.CustomerID, o.OrderID, o.NoToDisplay
FROM Customer c
LEFT OUTER JOIN Order o ON o.CustomerID = c.CustomerID
WHERE o.OrderID IN (SELECT DISTINCT o.NoToDisplay
FROM Customer c
LEFT OUTER JOIN Order o ON o.CustomerID = c.CustomerID
GROUP BY o.NoToDisplay HAVING COUNT(*) > 1)
You seem to want customers where the NoToDisplay values are all the same. To get the customers:
select customerid
from t
group by customerid
having min(NoToDisplay) = max(NoToDisplay);
You can easily extend this to get the original rows:
select t.*
from t join
(select customerid
from t
group by customerid
having min(NoToDisplay) = max(NoToDisplay)
) tc
on t.customerid = tc.customerid;
Try this:
select * from Customer
where customerid not in
(select customerid
from Customer
group by customerid
having count(distinct notodisplay) >1)
You can try below:
declare #Customer table
(CustomerId int, OrderId int, NoToDisplay int)
insert into #Customer
select 123 , 176 , 1 union all
select 123 , 177 , 1 union all
select 124 , 125 , 1 union all
select 124 , 126 , 2 union all
select 124 , 127 , 3 union all
select 125 , 182 , 6 union all
select 125 , 183 , 6
select CustomerID, OrderId, NoToDisplay
from
(select CustomerID, OrderId, NoToDisplay, count(*) OVER (PARTITION BY CustomerID, NoToDisplay) [check]
from #Customer
group by CustomerID, OrderID, NoToDisplay) x
where [check] > 1
order by CustomerID

Inner join without duplicate values from the left table?

I'm working with SQL Server, and I have 2 tables: Invoice and InvoiceService.
Invoice:
InvoiceID InvoiceDate InvoicePrice InvoicePaidAmount PatientID
----------------------------------------------------------------------------
1 01-01-2016 50 30 1
2 01-02-2016 100 100 2
InvoiceService:
ID InvoiceID ServiceName ServicePrice
-------------------------------------------------
1 1 Dermato 20
2 1 ophthalmo 30
3 2 General 100
My query:
select
ServiceName, ServicePrice, InvoiceID, InvoicePrice,
InvoicePaidAmount, PatientID
from
InvoiceService
inner join
Invoice on Invoice.InvoiceID = InvoiceService.InvoiceID
Result:
ServiceName ServicePrice InvoiceID InvoicePrice InvoicePaidAmount PatientID
Dermato 20 1 50 30 1
ophthalmo 30 1 50 30 1
General 100 2 100 100 2
I need to get non duplicate values from the left table :
when an invoice has more than 1 service I want that the invoice price and InvoicePaidAmount don't be repeated like this example:
ServiceName ServicePrice InvoiceID InvoicePrice InvoicePaidAmount PatientID
Dermato 20 1 50 30 1
ophthalmo 30 1 0 0 1
General 100 2 100 100 2
If I understand correctly, you want one invoice service to "really" match.
select s.ServiceName, s.ServicePrice, i.InvoiceID,
(case when seqnum = 1 then i.InvoicePrice else 0 end) as InvoicePrice,
(case when seqnum = 1 then i.InvoicePaidAmount else 0 end) as InvoicePaidAmount,
i.PatientID
from Invoice i join
(select s.*,
row_number() over (partition by s.InvoiceID order by s.id) as seqnum
from InvoiceService s
) s
on i.InvoiceID = s.InvoiceID

Compare Values Between Two Tables

I Have two tables, Table_A and Table_B.
I want result like the table result below, can someone help me with the SQL query?
Table_A
------------------
ID ITEM_ID QTY
------------------
1 100 2
2 101 3
3 102 5
4 103 2
------------------
Table_B
------------------
ID ITEM_ID QTY
1 100 2
2 101 4
3 102 4
4 104 2
5 105 1
------------------
RESULT
------------------
ITEM_ID QTY
100 0
101 1
102 -1
103 -2
104 2
105 1
------------------
Thanks.
You need a full join to get values from either table
select
isnull(a.item_id,b.item_id) as item_id, isnull(b.qty, 0) - isnull(a.qty, 0) as qty
from
table_a a
full outer join table_b b on a.item_id = b.item_id
select item_id, sum(qty)
from (select item_id, qty
from table_b
union all
select item_id, -qty
from table_a) x
group by item_id
order by item_id
Used full outer join and some isnulls
SQL Fiddle Example
select isnull(b.item_id, a.item_id) as ItemID,
isnull(b.qty, 0) - isnull(a.qty,0)as Qty
from table_b b
full outer join table_a a on a.item_id = b.item_id
order by itemid