I have a problem.
Table-1 Name : InvoiceDetail
InvoiceNo StockCode Piece
---------- ----------- ------
1 CP-001 10
1 CP-002 15
2 CP-001 18
2 MN-001 18
Table-2 Name : Stock
StockCode StockName
----------- -----------
CP-001 Computer-A
CP-002 Computer-B
MN-001 Monitor-A
Expected Result
InvoiceNo Description TotalPiece
---------- ----------------------- ----------
1 Computer-A, Computer-B 25
2 Computer-A, Monitor-A 36
I wrote the below query
Query
SELECT InvoiceNo,
(select StockName + '-' from Stock
where StockCode = Results.StockCode
order by StockName
FOR XML PATH('')) AS Description,
SUM(Piece) AS TotalPiece
FROM InvoiceDetail Results
GROUP BY InvoiceNo, Results.StockCode
ORDER BY InvoiceNo
And results
InvoiceNo Description TotalPiece
1 Computer-A- 10
1 Computer-B- 15
2 Computer-A- 18
2 Monitor-A- 18
Whats wrong?
Perform the group by separately in a CTE, and then you can safely concatenate the description as a separate step:
with InvoiceGroupings as (
select t.InvoiceNo,
sum(t.Piece) as TotalPiece
from InvoiceDetail t
group by t.InvoiceNo)
select g.InvoiceNo,
stuff((select ', ' + s.StockName
from InvoiceDetail i
join Stock s
on i.StockCode = s.StockCode
where i.InvoiceNo = g.InvoiceNo
order by s.StockName
for xml path('')),1,2,'') as Description,
g.TotalPiece
from InvoiceGroupings g
order by g.InvoiceNo
SQL Fiddle Demo
Related
Sorry this is my first post - please let me know if something doesn't make sense!
I'm trying to get a count of the number of orders with a specific code XXX ONLY
lets say table A looks something like this
|ORDER ID | ITEM CODE |
123 XXX
123 YYY
123 YYY
456 XXX
456 XXX
456 XXX
789 XXX
000 YYY
what i want in the output is:
order 123 and 000 not to count
and order 456 and 789 to count as 1 each
I only want the count of the unique orders which have item code XXX ONLY
so the count/ output of the final query should be 2
currently what i have is
select order_id, item code, count(order_id) from table a
where item code = 'XXX'
group by order_id, item code
order by count(order_id)
which outputs me the following
ORDER_ID | ITEM CODE | COUNT(ORDER_ID)
123 XXX 1
345 XXX 3
789 XXX 1
This is wrong because I want the output as described above
Thanks in advance!
select order_id
from table_a
group by order_id
having min(item_code) = 'XXX'
and max(item_code) = 'XXX'
Seems like you want this :
select distinct order_id , item_code , 1 as count
from table t1
where not exists (
select 1 from table t2
where t1.order_id = t2.order_id
and t2.item_code <> 'XXX'
)
the count would be always 1 per your question
One option is to use an anti-join. For example:
select distinct t.order_id, 1 as cnt
from table_a t
left join table_a u on u.order_id = t.order_id and u.item_code <> 'XXX'
where t.item_code = 'XXX' and u.order_id is null
Result:
ORDER_ID CNT
--------- ---
789 1
456 1
See running example at db<>fiddle.
EDIT
To get the total count only, tweak the query as shown below:
select count(distinct t.order_id) as cnt
from table_a t
left join table_a u on u.order_id = t.order_id and u.item_code <> 'XXX'
where t.item_code = 'XXX' and u.order_id is null
Result:
CNT
---
2
See running example at db<>fiddle.
I have the two tables as below :
SQL> select * from customer;
CUSTOMERID CUSTOMERNAME
---------- --------------
1 A
2 B
SQL> select * from cars;
CARID CUSTOMERID MODEL
---------- ---------- ----------
1 1 toyota
2 1 honda
3 2 suzuki
I need to write an SQL query which would give an output like below :
( Can we use PIVOT or UNPIVOT for this ? I am not sure ! )
CUSTOMERID CUSTOMERNAME Model1 Model2
---------- ------------- ------- --------
1 A toyota honda
2 B suzuki NULL
You can use window function & do conditional aggregation :
select customerid, customername,
max(case when seq = 1 then model end) as model1,
max(case when seq = 2 then model end) as model2
from (select c.*, cr.model,
row_number() over (partition by c.customerid order by cr.MODEL) as seq
from customer c inner join
cars cr
on cr.customerid = c.customerid
) t
group by customerid, customername;
If you have only two values, you can use aggregation:
select cu.customerid, cu.customername,
min(ca.model) as model1,
nullif(max(ca.model), min(ca.model)) as model2
from customers cu join
cars ca
on ca.customerid = cu.customerid
group by cu.customerid, cu.customername;
If you have an indeterminate number, I would recommend aggregating them into a string or array. That syntax depends on the database, but typical syntax is:
select cu.customerid, cu.customername,
listagg(ca.model, ',') within group (order by ca.model) as models
from customers cu join
cars ca
on ca.customerid = cu.customerid
group by cu.customerid, cu.customername;
Heck, maybe 'joining' isn't even involved. I'm way out of my sql league here. Could someone please help me out w/ the following:
Table A
ItemId ItemLookup Price
------- ---------- -----
1 123456 10.00
2 234567 7.00
3 345678 6.00
Table B
ItemId Location Qty QtyOnHold
------- ---------- ----- ---------
1 1 26 20
2 1 0 0
3 1 12 6
1 2 4 0
2 2 2 1
3 2 16 8
What I'm hoping to get is something that looks like
ItemLookup, Price, (qty minus qtyonhold for loc1), (qty minus qtyonhold for loc2)
or 123456, 10.00, 6, 4
Thank you very much for any direction you can provide.
You can use conditional aggregation and a join:
select a.ItemLookup,
sum(case when Location = 1 then Qty - QtyOnHold end) as Location1,
sum(case when Location = 2 then Qty - QtyOnHold end) as Location2
from tableb b join
tablea a
on b.ItemId = a.ItemId
group by a.ItemLookup;
Somthing like this
select tablea.* ,
(select (qty- QtyOnHold) as qty from tableb where ItemId = tablea.ItemId ans Location = 1 ) as qtyl1,
(select (qty- QtyOnHold) as qty from tableb where ItemId = tablea.ItemId ans Location = 2) as qtyl2
from tablea
This assumes that there's only one row in TableB for each ItemID + Location combination. This is basically just a "pivot", you can learn various ways to do this in MySQL here.
SELECT ItemLookup, Price,
MAX(IF(Location = 1, Qty-QtyOnHold, 0)) avail1,
MAX(IF(Location = 2, Qty-QtyOnHold, 0)) avail2
FROM TableA AS a
JOIN TableB AS b ON a.ItemId = b.ItemId
GROUP BY a.ItemId
It seems to me that it may be possible to have a variable number of locations for each item. If this is the case, you need an aggregate function to convert/concatenate multiple rows into a column.
Here's an example with MySQL's group_concat function:
select a.itemlookup,a.price,group_concat('loc ',location,'=',b.x order by location) as qty_minus_qtyonhold
from tablea a,(select itemid,location,qty-qty_onhold x from tableb
group by itemid,location) as b
where a.itemid = b.itemid
group by 1
You'll get a result like this:
itemlookup price qty_minus_qtyonhold
---------- ------ ------------------
123456 10.00 loc 1=6,loc 2=4
234567 7.00 loc 1=0,loc 2=1
345678 6.00 loc 1=6,loc 2=8
Not sure what DBMS you're using but there are similar alternatives for Oracle and SQL Server
I have a table like following:
GroupID ParentID Type
1 ABC IND
1 ABC IND
1 CDE ORD
1 EFG STD
2 ZZZ IND
2 ZZZ IND
2 ZZZ IND
3 YYY COR
3 YYY COR
I need to exclude those records that are in the same group, having the same parent ID and the type is IND or COR. But I need to keep those groups that have different parent ID and the type is not IND or COR.
So the result I want to get would be the following:
GroupID ParentID Type
1 ABC IND
1 ABC IND
1 CDE ORD
1 EFG STD
Somehow I am thinking to use
Rank () over(partition by GroupID order by ParentID), but it won't give me the results that I want.
Any thoughts? PS: This table has 5 Million+ records. Looking for the effective way to deal with it.
Thanks
The following gives you a list of the groupIDs you want to exclude
SELECT GroupID
FROM
(
SELECT GroupID,
COUNT(DISTINCT ParentID) AS PCount, COUNT(DISTINCT TypeCode) as TCount,
MAX(TypeCode) AS tCode
FROM tablename
GROUP BY GroupID
) t
WHERE PCount = 1 AND TCount = 1
AND (tCode = 'IND' OR tCode = 'COR')
Now select everything else
SELECT *
FROM tableName
WHERE GroupID not in (
SELECT GroupID
FROM
(
SELECT GroupID,
COUNT(DISTINCT ParentID) AS PCount, COUNT(DISTINCT TypeCode) as TCount,
MAX(TypeCode) AS tCode
FROM tablename
GROUP BY GroupID
) t
WHERE PCount = 1 AND TCount = 1
AND (tCode = 'IND' OR tCode = 'COR')
)
Test with fiddle --> http://sqlfiddle.com/#!3/f1d4f/15/0
How is
1 ABC IND
in result set? here type is IND and you mentioned the result set should not have type IND or COR?
Below are the 3 tables
QuotationMaster
QuoteID QuoteNo CustomerName
-----------------------------
1 Q1 Name1
2 Q2 Name2
3 Q3 Name3
4 Q4 Name4
5 Q5 Name5
QuoteItemDetails : one quote can have many items
QuoteItemID QuoteID ItemCode ItemID
---------------------------------------------
1 1 100 1
1 1 200 2
2 2 200 2
QuoteBatchDetails : one QuoteItem can have many batches of QuoteID and ItemID are the common columns. BatchNo is varchar
QuotebatchID QuoteID BatchNo ItemID
---------------------------------------------
1 1 A 1
2 1 B 1
3 1 C 2
4 2 E 2
5 2 F 2
I want the result as
QuoteID QuoteNo CustName ItemCode BatchNo
-------------------------------------------------
1 Q1 Name1 100 A,B
1 Q1 Name1 200 C
2 Q2 Name2 200 E,F
I want to create a procedure which takes QuoteID as parameter of INT type and get the result as above.
The only problem I am facing is to concatenate the BatchNo which depends on ItemID and further on QuoteID.
Using the below query I am able to concatenate the BatchNo for a particular ID but I am not sure how to add this to the main procedure, when I do that errors pops up like subquery returns more than one value.I understand because for every quote there can be more than 1 item.
select
ID.QuoteID,ID.ItemID,
stuff((select ', ' + BatchNo
from SD_QuoteBatchDetails BD where ID.ItemID=BD.ItemID and ID.QuoteID=BD.QuoteID
for xml path('')),
1,2,'') [Values]
from SD_QuoteItemDetails QID,SD_QuoteBatchDetails ID where ID.QuoteID=QID.QuoteID
group by ID.ItemID,ID.QuoteID
Can anyone provide a query for the same.
SELECT b.QuoteItemID,
a.QuoteNo,
a.CustomerName,
b.ItemCode,
c.BatchList
FROM QuotationMaster a
INNER JOIN QuoteItemDetails b
ON a.QuoteID = b.QuoteID
INNER JOIN
(
SELECT
QuoteID,
ItemID,
STUFF(
(SELECT ', ' + BatchNo
FROM QuoteBatchDetails
WHERE QuoteID = a.QuoteID AND
ItemID = a.ItemID
FOR XML PATH (''))
, 1, 1, '') AS BatchList
FROM QuoteBatchDetails AS a
GROUP BY QuoteID, ItemID
) c ON b.QuoteID = c.QuoteID AND
b.ItemID = c.ItemID;
SQLFiddle Demo