Error in query using WHERE IN - sql

This is the query I try to run:
Select Status from [transaction] where TransactionID IN (select MAX(CAST(TransactionID AS VARCHAR(36))), sum(debit)
FROM [transaction]
WHERE dbo.getday(StartSaleTime) >= '5/1/2011' and dbo.getday(StartSaleTime) <= '5/3/2011' and Status > -1 And TransactionNo like 'EL%' And TransactionType = 4
GROUP BY CustomerID, debit HAVING ( COUNT(CustomerID) > 1 ))
it returns this error:
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.

It tells you exactly what is wrong in the error message. When using in you can only specify one column in the select list.
If you change your query to this, it should work fine.
Select Status from [transaction] where TransactionID
IN (select MAX(CAST(TransactionID AS VARCHAR(36))) as [TransactionID]
FROM [transaction]
WHERE dbo.getday(StartSaleTime) >= '5/1/2011' and dbo.getday(StartSaleTime) <= '5/3/2011' and Status > -1 And TransactionNo like 'EL%' And TransactionType = 4
GROUP BY CustomerID, debit HAVING ( COUNT(CustomerID) > 1 ))
You can specify multiple columns but only when using EXISTS not IN

You are selecting two things and trying to use that with IN(). You should select only the ID when trying to do where someId In(list of Ids).

Your subquery has to return only a single field. Right now you're returning two, so the overall query looks kinda like:
SELECT ... WHERE TransactionID IN ((a,b), (c,d), etc...)
SQL server doesn't known which column to use for the IN stuff, so it's complaining.

Related

using correlated subquery in the case statement

I’m trying to use a correlated subquery in my sql code and I can't wrap my head around what I'm doing wrong. A brief description about the code and what I'm trying to do:
The code consists of a big query (ALIASED AS A) which result set looks like a list of customer IDs, offer IDs and response status name ("SOLD","SELLING","IRRELEVANT","NO ANSWER" etc.) of each customer to each offer. The customers IDs and the responses in the result set are non-unique, since more than one offer can be made to each customer, and a customer can have different response for different offers.
The goal is to generate a list of distinct customer IDs and to mark each ID with 0 or 1 flag :
if the ID has AT LEAST ONE offer with status name is "SOLD" or "SELLING" the flag should be 1 otherwise 0. Since each customer has an array of different responses, what I'm trying to do is to check if "SOLD" or "SELLING" appears in this array for each customer ID, using correlated subquery in the case statement and aliasing the big underlying query named A with A1 this time:
select distinct
A.customer_ID,
case when 'SOLD' in (select distinct A1.response from A as A1
where A.customer_ID = A1.customer_ID) OR
'SELLING' in (select distinct A1.response from A as A1
where A.customer_ID = A1.customer_ID)
then 1 else 0 end as FLAG
FROM
(select …) A
What I get is a mistake alert saying there is no such object as A or A1.
Thanks in advance for the help!
You can use exists with cte :
with cte as (
<query here>
)
select c.*,
(case when exists (select 1
from cte c1
where c1.customer_ID = c.customer_ID and
c1.response in ('sold', 'selling')
)
then 1 else 0
end) as flag
from cte c;
You can also do aggregation :
select customer_id,
max(case when a.response in ('sold', 'selling') then 1 else 0 end) as flag
from < query here > a;
group by customer_id;
With statement as suggested by Yogesh is a good option. If you have any performance issues with "WITH" statement. you can create a volatile table and use columns from volatile table in your select statement .
create voltaile table as (select response from where response in ('SOLD','SELLING').
SELECT from customer table < and join voltaile table>.
The only disadvantge here is volatile tables cannot be accessed after you disconnect from session.

Redshift - Finding number of times a flag appears for a particular ID

I have some sales data that shows if a bill has been generated for a customer. The column labelled bill_generated returns 'Y' if a bill has been generated else its blank. I am trying to find the list of customers for whom atleast one bill has been generated. There could be multiple rows for each cust_id as shown below:
cust_id, bill_generated
001,NULL
001,Y
002,NULL
002,NULL
003,Y
Could anyone advice on this. I am using Redshift DB. Thanks..
Try below using group by and having cluse
select cust_id from tablename
group by cust_id
having sum(case when bill_generated is null then 0 else 1 end)=1
you can use co-related sub-query
select * from t
where exists (select 1 from t t1
where t1.bill_generated='Y' and t1.cust_id=t.cust_id
)

Return a Complete sales order where a given item is purchased SQL

I'm trying to query our Sales_Order_Line_Item table. We are introducing a new "Tariff" Item code, our sales staff are required to add this code to all orders that have items that start with "WI". So I need to create a query that will show me any orders that have item codes that start with "WI" but are missing the "Tariff" code.
I can't seem to figure out how to return a list that shows this data.
For simplicity, my Sales_Order_Line_Item Table has these 3 columns:
UNIQUE_LINE_ID, SALE_ORDER_#, ITEM_#
One dirty trick is to use a case expression and count the number of times these items appear:
SELECT sale_order_no
FROM sales_order_line_item
GROUP BY sale_order_no
HAVING COUNT(CASE WHEN item_code LIKE 'WI%' THEN 1 END) > 0 AND
COUNT(CASE WHEN item_code = 'Tarrif' THEN 1 END) = 0
Should be something like this:
select * from Sales_Order_Line_Item
where ItemCode like 'wi%'
and tariff is null
If, you want full order details you can use EXISTS/NOT EXISTS instead :
select so.*
from sales_order_line_item so
where exists (select 1 from sales_order_line_item sol where sol.sale_order_no = s.sale_order_no and sol.item_code LIKE 'WI%') and
not exists (select 1 from sales_order_line_item sol where sol.sale_order_no = s.sale_order_no and sol.item_code = 'Tarrif');

Querying database for records that don't have a 2nd record canceling it out

I have a table where I'm trying to find a set of particular records. Here's what my table looks like...
tblA
ID VouchID Action Amount
1 177-17 Add 700
2 177-17 Update 1
3 198-01 Add 600
4 198-01 Update 620
So what happens here, is if a record was canceled/deleted, the action would be 'Update' and Amount would be updated to 1. In other words, the VouchID = 177-17, would not be counted/be selected in this query...
What I'm hoping to do here is only select records, that don't have a corresponding Update record with Amount = 1
Select distinct vouchID where Action='add'
However, this query does not take under consideration VoucherID's that have an 'update' action. Update action can be applied in two instances, in VouchID 177-17 the amount = 1 on action='update' that means, that the ADD action does not count, it's almost as if we removed the record all together (it's just there for record keeping). Another Update in case of VoucherID = 198-01, the update line and amount = 620, means that the Amount was updated by 20 to 620, that record i hope to be able to see in my end reuslt
Desired end result from above table:
ID VouchID Action Amount
3 198-01 Add 600
You could use LEAD (SQL Server 2012 and above):
WITH cte AS (
SELECT *, LEAD(Amount) OVER(PARTITION BY VouchID ORDER BY ID) AS next_amount
FROM table
)
SELECT *
FROM cte
WHERE (next_amount <> 1 OR next_amount IS NULL) AND Action='add';
EDIT
non-recursive CTE can be always replaced with simple subquery:
SELECT *
FROM (SELECT *,
LEAD(Amount) OVER(PARTITION BY VouchID ORDER BY ID) AS next_amount
FROM table) sub
WHERE (next_amount <> 1 OR next_amount IS NULL) AND Action='add';
EDIT:
Using EXISTS:
SELECT *
FROM table t1
WHERE Action='add'
AND NOT EXISTS (SELECT TOP 1
FROM table t2
WHERE t1.VouchId = t2.VouchId
AND Action='Update'
AND Amount = 1
ORDER BY ID ASC);
What I'm hoping to do here is only select records, that don't have a
corresponding Update record with Amount = 1
Seems easy enough with NOT EXISTS():
Select distinct vouchID FROM MyTable t1 where Action='add'
AND NOT EXISTS(SELECT * FROM MyTable t2
WHERE Action='Update'
AND Amount=1
AND t2.VouchId=t1.VouchId
Are you using SQL Server 2008 or better? If you are, I would try something like :
SELECT
ID, vouchID, Action, Amount
FROM tblA s
WHERE
Action='add'
AND NOT EXISTS(Select 1 from tblA l where l.vouchID = s.vouchID and l.Action = 'Update' and l.Amount = 1);

Find Duplicates in SQL and UPDATE them?

I'm trying to find all duplicates in a Table and change one of their values.
Now i use:
SELECT Amount
FROM Bids
GROUP BY Amount, AuctionID
HAVING ( COUNT(Amount) > 1 ) AND (AuctionID=1)
The problem that it returns only
Amount
23.6500
41.8800
42.3500
And not
Amount
23.6500
23.6500
41.8800
41.8800
42.3500
42.3500
So I can't UPDATE all the rows.
How can I get it the way I showed?
Thanks,
Dan
Just wrap it inside an IN query:
SELECT Amount
FROM Bids
WHERE Amount IN (
SELECT Amount
FROM Bids
GROUP BY Amount, AuctionID
HAVING ( COUNT(Amount) > 1 ) AND (AuctionID=1)
)
UPDATE: added UPDATE statement
UPDATE Bids
SET Burned = 1
WHERE Amount IN (
SELECT Amount
FROM Bids
GROUP BY Amount, AuctionID
HAVING ( COUNT(Amount) > 1 ) AND (AuctionID=1)
)
Assume that you have Id in Bids table:
SELECT Amount
FROM Bids b1
WHERE AcutionId = 1
AND EXISTS (Select 1 from Bids b2
WHERE b2.AuctionID = b1.AuctionId
AND b1.Amount = b2.Amount
AND b1.Id <> b2.Id)
I'm curious to know why your original select doesn't satisfy your requirement. If for every member within a set of duplicates you're only selecting one of them, then you have one to update. It should be informative to add AuctionId to the select provided by Frank Schmitt to see what distinguishes these rows.