A column in the predicate of the SQL - sql

How can I select custType in the predicate section of the query
I can't do so now because
Error code -1, SQL state 42X04: Column 'CUSTTYPE' is either not in any table in the FROM list or appears within a join specification and is outside the scope of the join specification or appears in a HAVING clause and is not in the GROUP BY list. If this is a CREATE or ALTER TABLE statement then 'CUSTTYPE' is not a column in the target table.
select p.SKU AS GiftID, p.ProductName AS GiftName,
case when sa.Sales >= v.LevelUpAmount then 1 else 2 end AS custType
from products p, campaign ca, SubCategory sc,
VIPLevelUpParam v,
ActiveParam a, customer c,
(select c.CustomerCode, sum(od.NetSales) AS Sales from customer c
INNER JOIN orders o ON (c.CustomerCode = o.CustomerCode)
INNER JOIN order_details od ON (o.OrderCode = od.OrderCode)
group by c.CustomerCode ) sa
where ca.CUSTOMERTYPE = custType AND
c.CustomerCode = 'CUS000001-2013-11-06' AND
p.SubCategoryID = sc.SubCategoryCode AND
p.SKU = ca.GiftID AND
sc.SubCategoryName = 'Gift'AND
v.LevelUpID = a.ActiveID AND
a.TableName = 'VIPLevelUpParam'
group by p.SKU, p.ProductName, sa.Sales, v.LevelUpAmount, custType;
Any one shed some light on this, it would be greatly appreciated!

As per logical query processing where clause is evaluated before select statement that why you're getting CustType column won't be available in where clause.
http://blog.sqlauthority.com/2009/04/06/sql-server-logical-query-processing-phases-order-of-statement-execution/
select * from
(
select p.SKU AS GiftID, p.ProductName AS GiftName,
case when sa.Sales >= v.LevelUpAmount then 1 else 2 end AS custType
from products p, campaign ca, SubCategory sc,
VIPLevelUpParam v,
ActiveParam a, customer c,
(select c.CustomerCode, sum(od.NetSales) AS Sales from customer c
INNER JOIN orders o ON (c.CustomerCode = o.CustomerCode)
INNER JOIN order_details od ON (o.OrderCode = od.OrderCode)
group by c.CustomerCode ) sa
) DT
where DT.CUSTOMERTYPE = DT.custType AND
DT.CustomerCode = 'CUS000001-2013-11-06' AND
DT.SubCategoryID = DT.SubCategoryCode AND
DT.SKU = DT.GiftID AND
DT.SubCategoryName = 'Gift' AND
DT.LevelUpID = DT.ActiveID AND
DT.TableName = 'VIPLevelUpParam'
group by DT.SKU, DT.ProductName, DT.Sales, DT.LevelUpAmount, DT.custType;

Related

Oracle SQL How to Count Column Value Occurences and Group BY during joins

I'm working on another SQL query, trying to group a collection of records while doing a count and joining tables. See below for goal, current query, and attached scripts for building and populating tables.
Show all customers who have checked more books than DVDs. Display
customer name, total book checkouts and total DVD checkouts. Sort
results by customer first name and last name.
SELECT C.CUSTOMER_FIRSTNAME, C.CUSTOMER_LASTNAME, COUNT(T.TRANSACTION_ID)
FROM customer C
INNER JOIN library_card LC ON C.CUSTOMER_ID = LC.CUSTOMER_ID
INNER JOIN transaction T ON LC.LIBRARY_CARD_ID = T.LIBRARY_CARD_ID
INNER JOIN physical_item P ON T.PHYSICAL_ITEM_ID = P.PHYSICAL_ITEM_ID
INNER JOIN catalog_item CT ON P.CATALOG_ITEM_ID = CT.CATALOG_ITEM_ID
GROUP BY C.CUSTOMER_FIRSTNAME, C.CUSTOMER_LASTNAME
ORDER BY C.CUSTOMER_FIRSTNAME, C.CUSTOMER_LASTNAME;
Run first: https://drive.google.com/open?id=1PYAZV4KIfZtxP4eQn35zsczySsxDM7ls
Run second: https://drive.google.com/open?id=1pAzWmJqvD3o3n6YJqVUM6TtxDafKGd3f
EDIT
With some help from Mr. Barbaros I've come up with the below query, which is closer. However, this query isn't returning any results for DVDs, which leads me to believe it's a join issue.
SELECT C.CUSTOMER_FIRSTNAME, C.CUSTOMER_LASTNAME, COUNT(CT1.TYPE) AS BOOK_COUNT, COUNT(CT2.TYPE) AS DVD_COUNT
FROM customer C
INNER JOIN library_card LC ON C.CUSTOMER_ID = LC.CUSTOMER_ID
INNER JOIN transaction T ON LC.LIBRARY_CARD_ID = T.LIBRARY_CARD_ID
INNER JOIN physical_item P ON T.PHYSICAL_ITEM_ID = P.PHYSICAL_ITEM_ID
INNER JOIN catalog_item CT1 ON P.CATALOG_ITEM_ID = CT1.CATALOG_ITEM_ID AND CT1.TYPE = 'BOOK'
LEFT OUTER JOIN catalog_item CT2 ON P.CATALOG_ITEM_ID = CT2.CATALOG_ITEM_ID AND CT2.TYPE = 'DVD'
GROUP BY C.CUSTOMER_FIRSTNAME, C.CUSTOMER_LASTNAME, CT1.TYPE, CT2.TYPE
ORDER BY C.CUSTOMER_FIRSTNAME, C.CUSTOMER_LASTNAME;
Use "conditional aggregates" (use a case expression inside the aggregate function)
SELECT
C.CUSTOMER_FIRSTNAME
, C.CUSTOMER_LASTNAME
, COUNT( CASE WHEN CT.TYPE = 'BOOK' THEN T.TRANSACTION_ID END ) books
, COUNT( CASE WHEN CT.TYPE = 'DVD' THEN T.TRANSACTION_ID END ) dvds
FROM customer C
INNER JOIN library_card LC ON C.CUSTOMER_ID = LC.CUSTOMER_ID
INNER JOIN transaction T ON LC.LIBRARY_CARD_ID = T.LIBRARY_CARD_ID
INNER JOIN physical_item P ON T.PHYSICAL_ITEM_ID = P.PHYSICAL_ITEM_ID
INNER JOIN catalog_item CT ON P.CATALOG_ITEM_ID = CT.CATALOG_ITEM_ID
GROUP BY
C.CUSTOMER_FIRSTNAME
, C.CUSTOMER_LASTNAME
HAVING
COUNT( CASE WHEN CT.TYPE = 'BOOK' THEN T.TRANSACTION_ID END )
> COUNT( CASE WHEN CT.TYPE = 'DVD' THEN T.TRANSACTION_ID END )
ORDER BY
C.CUSTOMER_FIRSTNAME
, C.CUSTOMER_LASTNAME
;
You can use catalog_item table twice( think of as seperate tables for books and dvds ), and compare by HAVING clause as :
SELECT C.CUSTOMER_FIRSTNAME, C.CUSTOMER_LASTNAME,
COUNT(CT1.CATALOG_ITEM_ID) as "Book Checkout",
COUNT(CT2.CATALOG_ITEM_ID) as "DVD Checkout"
FROM customer C
INNER JOIN library_card LC ON C.CUSTOMER_ID = LC.CUSTOMER_ID
INNER JOIN transaction T ON LC.LIBRARY_CARD_ID = T.LIBRARY_CARD_ID
INNER JOIN physical_item P ON T.PHYSICAL_ITEM_ID = P.PHYSICAL_ITEM_ID
LEFT JOIN catalog_item CT1 ON P.CATALOG_ITEM_ID = CT1.CATALOG_ITEM_ID AND CT1.TYPE = 'BOOK'
LEFT JOIN catalog_item CT2 ON P.CATALOG_ITEM_ID = CT2.CATALOG_ITEM_ID AND CT1.TYPE = 'DVD'
GROUP BY C.CUSTOMER_FIRSTNAME, C.CUSTOMER_LASTNAME
HAVING COUNT(CT1.CATALOG_ITEM_ID) > COUNT(CT2.CATALOG_ITEM_ID)
ORDER BY C.CUSTOMER_FIRSTNAME, C.CUSTOMER_LASTNAME;
CUSTOMER_FIRSTNAME CUSTOMER_LASTNAME Book Checkout DVD Checkout
------------------ ----------------- ------------- -------------
Deena Pilgrim 3 1
Emile Cross 5 2
Please try to remove ,CT1.TYPE, CT2.TYPE on your group by clause.

Join SQL query not giving desired result

I have separate queries with me as follows:
SELECT c.id
FROM claim c,
company co,
customer cu
WHERE c.company_id = co.id
AND c.customer_id = cu.id
AND co.company_code = 'LTO'
AND cu.customer_no = '021540'
AND c.invoice_number IS NOT NULL
AND c.invoice_date IS NULL
AND c.invoice_number = '20170331'
SELECT Sum(price)
FROM replaced_part
WHERE claim_id IN ( 628099, 674047, 1182523, 1282549,
1479834, 1480585, 1487452, 1515238 );
SELECT Sum(price)
FROM allowance
WHERE claim_id IN ( 628099, 674047, 1182523, 1282549,
1479834, 1480585, 1487452, 1515238 );
I was trying to group together all the above queries into one using sql equi join as follows:
select co.company_Code,
cu.customer_No,
c.invoice_Number,
sum(r.price),
sum(a.price)
FROM claim c INNER JOIN company co ON c.COMPANY_ID=co.ID
INNER JOIN customer cu ON c.CUSTOMER_ID=cu.ID
INNER JOIN replaced_part r ON r.claim_id=c.id
INNER JOIN allowance a ON a.claim_id = c.id
WHERE co.company_code = 'LTO' and cu.customer_no='021540' and
c.INVOICE_NUMBER is not null and c.INVOICE_DATE is null and
c.INVOICE_NUMBER='20170331'
GROUP BY co.company_Code, cu.customer_No, c.invoice_Number
But I am not getting the desired result(Query execute successfully but the sum is incorrect) as I am getting after running the 3 separate queries defined above... What is the problem here in my query created using equi join??
Relationship between tables are claim ->(one to one) -> company ->(one to one) -> customer ->(one to many) ->Replaced_Part ->(one to many) -> allowance
Please try to use left join for Replaced_Part and allowance
select co.company_Code
, cu.customer_No
, c.invoice_Number
, (SELECT sum(r.price) FROM replaced_part r WHERE r.claim_id = c.id)
, (SELECT sum(a.price) FROM allowance a WHERE a.claim_id = c.id)
FROM claim c
INNER JOIN company co
ON c.COMPANY_ID=co.ID
INNER JOIN customer cu
ON c.CUSTOMER_ID=cu.ID
WHERE co.company_code = 'LTO'
AND cu.customer_no='021540'
AND c.INVOICE_DATE is null
AND c.INVOICE_NUMBER='20170331'
GROUP BY co.company_Code
, cu.customer_No
, c.invoice_Number
try to use temporary table, combine all the tables and make a temporary table, then fire your conditions on that table.
Example :
select co.company_Code,
cu.customer_No,
c.invoice_Number,
sum(r.price),
sum(a.price)
into #temp from (claim c
INNER JOIN company co ON c.COMPANY_ID=co.ID
INNER JOIN customer cu ON c.CUSTOMER_ID=cu.ID
INNER JOIN replaced_part r ON r.claim_id=c.id
INNER JOIN allowance a ON a.claim_id = c.id
and then use your conditions on #temp. like
select * from #temp
WHERE company_code = 'LTO' and customer_no='021540' and
INVOICE_NUMBER is not null and INVOICE_DATE is null and
INVOICE_NUMBER='20170331'
GROUP BY company_Code, customer_No, invoice_Number
Hope this will work for you.

Too many results in query

I'm fetching some data from our database in MSSQL. Out of this data I want to determine who created the client entry and who took the first payment from this client.
There can be many payment entries for a client on a single booking/enquiry and at the moment, my query shows results for each payment. How can I limit the output to only show the first payment entry?
My query:
SELECT
c.FirstName,
c.LastName,
c.PostalCode,
o.OriginOfEnquiry,
s.SuperOriginName,
c.DateOfCreation,
DATEDIFF(day, c.DateOfCreation, p.DateOfCreation) AS DaysToPayment,
pc.PackageName,
CONCAT(u.FirstName, ' ', u.LastName) AS CreateUser,
(SELECT CONCAT(u.FirstName, ' ', u.LastName)
WHERE u.UserID = p.UserID ) AS PaymentUser
FROM tblBookings b
INNER JOIN tblPayments p
ON b.BookingID = p.BookingID
INNER JOIN tblEnquiries e
ON e.EnquiryID = b.EnquiryID
INNER JOIN tblCustomers c
ON c.CustomerID = e.CustomerID
INNER JOIN tblOrigins o
ON o.OriginID = e.OriginID
INNER JOIN tblSuperOrigins s
ON s.SuperOriginID = o.SuperOriginID
INNER JOIN tblBookingPackages bp
ON bp.bookingID = p.BookingID
INNER JOIN tblPackages pc
ON pc.PackageID = bp.packageID
INNER JOIN tblUsers u
ON u.UserID = c.UserID
WHERE c.DateOfCreation >= '2016-06-01' AND c.DateOfCreation < '2016-06-30'
AND p.PaymentStatusID IN (1,2)
AND e.CustomerID = c.CustomerID
AND p.DeleteMark != 1
AND c.DeleteMark != 1
AND b.DeleteMark != 1
;
I tried adding a "TOP 1" to the nested select statement for PaymentUser, but it made no difference.
you can use cross apply with top 1:
FROM tblBookings b
cross apply
(select top 1 * from tblPayments p where b.BookingID = p.BookingID) as p
Instead of table tblPayments specify sub-query like this:
(SELECT TOP 1 BookingID, UserID, DateOfCreation
FROM tblPayments
WHERE DeleteMark != 1
AND PaymentStatusID IN (1,2)
ORDER BY DateOfCreation) as p
I'm assuming that tblPayments has a primary key column ID. If it is true, you can use this statment:
FROM tblBookings b
INNER JOIN tblPayments p ON p.ID = (
SELECT TOP 1 ID
FROM tblPayments
WHERE BookingID = b.BookingID
AND DeleteMark != 1
AND PaymentStatusID IN (1,2)
ORDER BY DateOfCreation)

Informix: Query merge

i have 2 queries:
select COUNT(o.id_offer) from offers o, product p where
p.id_product = "+ productID +" and o.id_offer = "+ offerID +" and (b.type = 0 or o.type = "A")
this query returns the count of some product
select p.id_product, p.name, s.id_supplier, s.name from product p, suppliers s where p.id_supplier = s.id_supplier
this query returns all products data
i want to combine the two queries in one, something like this:
select (select COUNT(o.id_offer) from offers o, product p where
p.id_product = p.id_product and o.id_offer = 13345 and (b.type = 0 or o.type = "A")) count,p.id_product, p.name, s.id_supplier, s.name from product p, suppliers s where p.id_supplier = s.id_supplier
Anyone knows how to do this in informix?
Please use the explicit join notation, not the comma-list of table names in the FROM clause notation.
The first query needs generalizing to generate a product ID and the matching count.
SELECT p.id_product, COUNT(o.id_offer) AS offer_count
FROM offers o
JOIN product p ON p.id_product = o.id_product -- Guessed column
WHERE (p.type = 0 OR o.type = 'A')
GROUP BY p.id_product
The second query can be converted to:
SELECT p.id_product, p.name, s.id_supplier, s.name
FROM product p
JOIN suppliers s ON p.id_supplier = s.id_supplier
These two queries can be combined with a join, too:
SELECT x.id_product, x.product_name, x.id_supplier, x.supplier_name, y.offer_count
FROM (SELECT p.id_product, p.name, s.id_supplier, s.name
FROM product p
JOIN suppliers s ON p.id_supplier = s.id_supplier
) AS x
JOIN (SELECT p.id_product, COUNT(o.id_offer) AS offer_count
FROM offers o
JOIN product p ON p.id_product = o.id_product -- Guessed column
WHERE (p.type = 0 OR o.type = 'A')
GROUP BY p.id_product
) AS y
ON x.id_product = y.id_product

how to check if a type of row exists in a table

Hi I have an order table and a payment table which are linked by order_num. I would like to get entries from order table who have entries in the payment table of PaymentType 'A' as well as PaymentType 'B' and their amounts match. Example order number 411 should only be returned to me if it has at least two payments and one of them is paymenttype 'A' and the other one is paymenttype 'b' and amount for both is 45
Thanks.
Like the comments state, there is very little info to go off of for a truly definitive answer. Here goes a possible solution, at least in a basic form.
SELECT *
FROM Orders o
LEFT JOIN Payment p1 ON o.order_num = p1.order_num
LEFT JOIN Payment p2 ON o.order_num = p2.order_num
WHERE p1.Type = "A"
AND p2.Type = "B"
AND p1.Amount = p2.Amount
As long as you can guarantee that there are at most one A and one B row:
SELECT
<columns here>
FROM
Orders O
INNER JOIN Payments PA ON
PA.order_number = O.order_number AND
PA.payment_type = 'A'
INNER JOIN Payments PB ON
PB.order_number = O.order_number AND
PB.payment_type = 'B'
WHERE
PA.amount = PB.amount
How about this:
SELECT o.OrderID,
o.Amount
FROM Order AS o
INNER JOIN Payment AS pA ON pA.OrderID = o.OrderID AND pA.PaymentType = 'A'
INNER JOIN Payment AS pB ON pB.OrderID = o.OrderID AND pB.PaymentType = 'B'
WHERE pA.Amount = pB.Amount
GROUP BY o.OrderID,
o.Amount
Making some (hopefully) reasonable assumptions about the names of tables, columns, etc, how about...
SELECT *
FROM ORDER_TABLE
WHERE EXISTS (SELECT *
FROM PAYMENT_TABLE
WHERE PAYMENT_TYPE = 'A' AND
PAYMENT_TABLE.ORDER = ORDER_TABLE.ORDER AND
PAYMENT_TABLE.AMOUNT = ORDER_TABLE.AMOUNT) AND
EXISTS (SELECT *
FROM PAYMENT_TABLE
WHERE PAYMENT_TYPE = 'B' AND
PAYMENT_TABLE.ORDER = ORDER_TABLE.ORDER AND
PAYMENT_TABLE.AMOUNT = ORDER_TABLE.AMOUNT);
Assumes amounts exist only in the payment table, and that the payment table may have multiple records for a payment type.
select [columns]
from ORDER O
where exists (select null from PAYMENT PA, PAYMENT PB
where PA.PAYMENT_TYPE = 'A'
and PB.PAYMENT_TYPE = 'B'
and PA.ORDER_NUM = O.ORDER_NUM
and PB.ORDER_NUM = O.ORDER_NUM
and PA.AMOUNT = PB.AMOUNT)