store select result in variable and use in where condition - sql

A have 3 SQL queries that I put together using union.
The first 2 queries return unique Order ID's but the third query repeats Order ID's from the first 2.I need to exclude those results in query 3 .
Example:
QUERY 1:
SELECT DISTINCT
ORDER_ID,
PRODUCT
FROM
ORDERS
WHEN TYPE=A
query 1 sample data {12121212,13131313}
QUERY 2:
SELECT DISTINCT
ORDER_ID,
PRODUCT,
FROM
ORDERS
WHEN CATEGORY=X
Query 2 sample data {14141414,15151515}
QUERY 3:
SELECT DISTINCT
ORDER_ID,
PRODUCT
FROM
ORDERS
WHEN TYPE=C
Query 3 sample data {17171717,12121212,14141414}
So query 3 repeats data from query 1 and 2. The real data is much larger. What I am trying to is to use the results of the first 2 queries to be excluded from query3
query1
union
query2
union
SELECT DISTINCT
ORDER_ID,
PRODUCT
FROM
ORDERS
WHEN TYPE=C
AND
ORDER_ID NOT IN (Variable1=ORDER_ID IN QUERY1,Variable2=ORDER_ID IN QUERY2)
Desired data {12121212,13131313,14141414,15151515,16161616,17171717}
How can I store variables to use in the where condition ?
Appreciate any help

It seems (but it is really hard to guess with any certainty) that you maybe want to do hierarchical data gathering, whether data is selected from 1st available source (from prioritized list), that has it, and next sources would get ignored.
Best of all I think would be making a persistent table having it all:
ORDER_ID, PRODUCT, Source_Priority
Such a table would track up-to-date data from all the tables (for example by AFTER UPADTE OR INSERT OR DELETE trigger on ORDERS and other sources) and then your query would be reformulated as "query new table, get rows with maximum-per-ORDER_ID-value-of-Source_Priority", which was asked many times, and is solved by one JOIN in Firebird 2 or by Window Functions in Firebird 3.
If you do not want to have a dedicated persistent prioritized table, You can do it, using
Global Temporary Table to do the sorting
https://firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-ddl-tbl.html#fblangref25-ddl-tbl-gtt
MERGE command to do conditional inserts (clearing the table before it)
https://firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-dml-merge.html
SELECT to read the data from prepared GTT
If you want to pretend that would be one query, not 2+N, then you can hide them inside
a named Stored Procedure or an anonymous EXECUTE BLOCK https://firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-dml-execblock.html
Something like that:
Create GLOBAL TEMPORARY TABLE TMP_ORDERS
( ORDER_ID integer PRIMARY KEY,
PRODUCT VarChar(10) );
And then replace your "one true query" with this sequence (maybe hidden inside the Execution Block if need be)
DELETE FROM TMP_ORDERS;
INSERT INTO TMP_ORDERS
SELECT DISTINCT
ORDER_ID,
PRODUCT
FROM
ORDERS
WHEN TYPE=A;
MERGE INTO TMP_ORDERS as Dest
USING (
SELECT DISTINCT
ORDER_ID,
PRODUCT,
FROM
ORDERS
WHEN CATEGORY=X
) as Src
WHEN NOT MATCHED THEN
INSERT(Dest.ORDER_ID, Dest.PRODUCT) VALUES(Src.ORDER_ID, Src.PRODUCT);
MERGE INTO TMP_ORDERS as Dest
USING (
SELECT DISTINCT
ORDER_ID,
PRODUCT,
FROM
ORDERS
WHEN TYPE=C) as Src
WHEN NOT MATCHED THEN
INSERT(Dest.ORDER_ID, Dest.PRODUCT) VALUES(Src.ORDER_ID, Src.PRODUCT);
SELECT * FROM TMP_ORDERS;
P.S. but why did your partial queries even contained DISTINCT ? Isn't ORDER_ID already your primary key there, which can never be non-distinct, to start with?

you can try this
select * from
(SELECT DISTINCT
ORDER_ID,
PRODUCT
FROM
ORDERS
where TYPE='A') as q1,
(SELECT DISTINCT
ORDER_ID,
PRODUCT
FROM
ORDERS
WHERE CATEGORY='X'
) as q2,
(SELECT DISTINCT
ORDER_ID,
PRODUCT
FROM
ORDERS
where TYPE='C') as q3
WHERE q1.order_id=q2.order_id

Related

Join query in Access 2013

Currently have a single table with large amount of data in access, due to the size I couldn't easily work with it in Excel any more.
I'm partially there on a query to pull data from this table.
7 Column table
One column GL_GL_NUM contains a transaction number. ~ 75% of these numbers are pairs. I'm trying to pull the records (all columns information) for each unique transaction number in this column.
I have put together some code from googling that hypothetically should work but I think I'm missing something on the syntax or simply asking access to do what it cannot.
See below:
SELECT SOURCE_FUND, GLType, Contract, Status, Debit, Credit, GL_GL_NUM
FROM Suspense
JOIN (
SELECT TC_TXN_NUM TXN_NUM, COUNT(GL_GL_NUM) GL_NUM
FROM Suspense
GROUP BY TC_TXN_NUM HAVING COUNT(GL_GL_NUM) > 1 ) SUB ON GL_GL_NUM = GL_NUM
Hey Beth is this the suggested code? It says there is a syntax error in the FROM clause. Thanks.
SELECT * from SuspenseGL
JOIN (
SELECT TC_TXN_NUM, COUNT(GL_GL_NUM) GL_NUM
FROM Suspense
GROUP BY TC_TXN_NUM
HAVING COUNT(GL_GL_NUM) > 1
Do you want detailed results (all rows and columns) or aggregate results, with one row per tx number?
If you want an aggregate result, like the count of distinct transaction numbers, then you need to apply one or more aggregate functions to any other columns you include.
If you run
SELECT TC_TXN_NUM, COUNT(GL_GL_NUM) GL_NUM
FROM Suspense
GROUP BY TC_TXN_NUM
HAVING COUNT(GL_GL_NUM) > 1
you'll get one row for each distinct txn, but if you then join those results back with your original table, you'll have the same number of rows as if you didn't join them with distinct txns at all.
Is there a column you don't want included in your results? If not, then the only query you need to work with is
select * from suspense
Considering your column names, what you may want is:
SELECT SOURCE_FUND, GLType, Contract, Status, sum(Debit) as sum_debit,
sum(Credit) as sum_credit, count(*) as txCount
FROM Suspense
group by
SOURCE_FUND, GLType, Contract, Status
based on your comments, if you can't work with aggregate results, you need to work with them all:
Select * from suspense
What's not working? It doesn't matter if 75% of the txns are duplicates, you need to send out every column in every row.
OK, let's say
Select * from suspense
returns 8 rows, and
select GL_GL_NUM from suspense group by GL_GL_NUM
returns 5 rows, because 3 of them have duplicate GL_GL_NUMs and 2 of them don't.
How many rows do you want in your result set? if you want less than 8 rows back, you need to perform some sort of aggregate function on each column you want returned.
You could do something like the following:
SELECT S.* FROM
SUSPENSE AS S
INNER JOIN (SELECT DISTINCT GL_GL_NUM, MIN(ID) AS ID FROM SUSPENSE
GROUP BY GL_GL_NUM) AS S2
ON S.ID = S2.ID
AND S.GL_GL_NUM = S2.GL_GL_NUM
Which would return a single row for a unique gl_gl_num. However if the other rows have different data it will not be shown. You would have to either aggregate that data up using SUM(Credit), SUM(Debit) and then GROUP BY the gl_gl_num.
I have attached a SQL Fiddle to demonstrate my results and make this clearer.
http://sqlfiddle.com/#!3/8284f/2

Counting payment types and assigning labels to clients based on most common orders

I have a large table of orders with 20+ columns. Within this there are ACCOUNT_ID and PAYMENT_TYPE.
I'd like to have three separate tables, based on preferred (most common) payment type.
I can count the payment type for each client easily enough, but have no idea as to the logic behind achieving what I need.
Hoping someone can point me int he right direction?
Please let me know if this is not clear, or an example is needed
Assuming you wanted the tables split as different payment types, use views and not separate tables or each time you insert a row into Orders, you need to also insert into the relevant Order[PaymentType] table through some mechanism (manually, trigger etc).
As W3schools puts it:
In SQL, a view is a virtual table based on the result-set of an SQL
statement.
You define a query that returns a result set, then you can treat that like you would a table. This means as you insert rows into Orders, you can view them in your view if they match the conditions, you do not need to worry about updating another table.
Assuming you wish to split them on payment types, and you had a similar payment type table as the following:
PaymentTypeId PaymentTypeDesc
----------------------------------
1 Cash
2 Cheque
3 Credit Card
then the following might be what you're looking for.
CREATE VIEW vw_OrdersCash AS
SELECT *
FROM Orders
WHERE PAYMENT_TYPE = 1
CREATE VIEW vw_OrdersCheque AS
SELECT *
FROM Orders
WHERE PAYMENT_TYPE = 2
CREATE VIEW vw_OrdersCreditCard AS
SELECT *
FROM Orders
WHERE PAYMENT_TYPE = 3
Just treat them as tables to do whatever you wish.
SELECT * FROM vw_OrdersCash
EDIT:
Reading one of your comments to your question, it sounds like you want it more dynamic than the suggestion above. It's hard to tell without sample output what it is you're trying to achieve, but if you wanted 3 dynamic tables you could extend the above, and rather than the views filtering to a specific payment type, they would filter to the 1st, 2nd and 3rd most common at the time of execution.
An idea of how to do this is below. The lookup view vw_OrdersTopThreePaymentMethods looks at the orders table and returns the top three payment types in descending order of number of orders (ie 1st, 2nd, 3rd). There are then views that will grab all of the orders on that specific type, with all the order information available for you to query as you want.
-- A lookup view that returns the top 3 payment methods of orders
CREATE VIEW vw_OrdersTopThreePaymentMethods AS
SELECT TOP 3
ROW_NUMBER() OVER(ORDER BY a.OrderCount DESC) AS Row,
PAYMENT_TYPE,
OrderCount
FROM (
SELECT PAYMENT_TYPE , COUNT(*) as 'OrderCount'
FROM Orders
GROUP BY PAYMENT_TYPE
) a
ORDER BY a.OrderCount desc
-- 3 views that then get the orders for the top three methods based on output of vw_OrdersTopThreePaymentMethods
CREATE VIEW vw_OrdersPrimaryPayment AS
SELECT *
FROM Orders
WHERE PAYMENT_TYPE IN (
SELECT PAYMENT_TYPE
FROM vw_OrdersTopThreePaymentMethods
WHERE Row = 1
)
CREATE VIEW vw_OrdersSecondaryPayment AS
SELECT *
FROM Orders
WHERE PAYMENT_TYPE IN (
SELECT PAYMENT_TYPE
FROM vw_OrdersTopThreePaymentMethods
WHERE Row = 2
)
CREATE VIEW vw_OrdersTertiaryPayment AS
SELECT *
FROM Orders
WHERE PAYMENT_TYPE IN (
SELECT PAYMENT_TYPE
FROM vw_OrdersTopThreePaymentMethods
WHERE Row = 3
)

Trying to do a SQL Merge statement, but it errors

I've got a stored procedure that accepts batches of product info. For each product, either insert it into the DB or Update it, if it already exists.
A product is defined by a composite key -> ProductCompanyId (where the product came from) and a ProductId (the unique Id, per company).
I'm trying to do a MERGE query. It works perfectly, until the batch has the same composite key in it more than once.
For example, lets imagine I have 10 products. 2 of these have the same comp-keys but different prices.
I thought the first 'row' would be inserted, with the 2nd row being an update.
Here is some FULL REPO sql code to show you what I've done.
It's far too hard to try and make sure there's only unique composite key's per batch. So, is there anything I can do?
I'm using SQL Server 2012 .. so I'm not sure if that's an issue.
Instead of using #MergeData directly as source of your MERGE statement, you could (should) rewrite it to use subquery or CTE that will filter duplicate rows and choose the correct one to be used in MERGE
WITH CTE_MergeData AS
(
SELECT *
, ROW_NUMBER() OVER (PARTITION BY ProductCompanyId, ProductId ORDER BY ProductId DESC) RN --find some better order
FROM #MergeData
)
MERGE INTO #SomeTable T
USING (SELECT * FROM CTE_MergeData WHERE RN = 1) S
ON T.ProductCompanyId = S.ProductCompanyId AND T.ProductId = S.ProductId
WHEN MATCHED THEN
UPDATE
SET T.Name = S.Name,
T.Price = S.Price
WHEN NOT MATCHED THEN
INSERT (ProductCompanyId, ProductId, Name, Price)
VALUES (S.ProductCompanyId, S.ProductId, S.Name, S.Price)
OUTPUT S.ProductCompanyId, S.ProductId, Inserted.Id INTO #MergeProductsResults;

select column from child table in select clause

Is there any way in SQL server to get the child records to be displayed as the fields of the select clause of master table?
Suppose a master table Sales and a child table called Purchaseditems.
The SaleId is referenced in the Purchaseitems table.
So for a sale, there are lot of purchase items.
If so, how I can write a query to select each sales with its purchased items in the select clause?
This is a kind of dynamic column selection from child table. Is this possible in SQL server?
Not sure if i'm getting the wrong idea here, but isn't this just a simple join:
select s.saleid, p.*
from sales s, purchaseditems p
where s.salesid = p.salesid;

how to query access to select entire records given a distinct criteria

I want to select the entire first row of each record where a promo code is unique. I am trying to create a samples table, in this table will be one record (the first record) from each distinct promo code. I have asked all of my co-workers and they usually go though the data by hand and select one from each. the problem is that the number of promo codes grows each time and the codes change. so I want to write a query that will select the first record found to have each distinct code. so for I have something like this:
SELECT DISTINCT Customer.promo1 FROM Customer AS promo;
SELECT * FROM Customer, promo
WHERE Customer.promo1 = promo.promo1;
But this obviously give the original table. I do have a ID field called AutoID in Customer.
Thanks in advance.
I'm assuming you want the first Customer.AutoId associated with each Customer.Promo
SELECT
c.*
FROM
Customer c
INNER JOIN
(
SELECT
c.promo1,
MIN(c.AutoID) AutoID
FROM
Customer c
GROUP BY
c.promo1) FirstCusomterWithPromo
ON c.AutoID = FirstCusomterWithPromo.AutoID
Something like that:
SELECT * FROM Customer
GROUP BY Customer.promo1