SQLAlchemy - Duplicates counter column - sqlalchemy

I need some help in transforming the following query into one SQLAlchemy statement:
select c.id,
c.first_name,
c.middle_name,
c.last_name,
cd.dups -- THIS IS A COLUMN WHICH IS NOT MAPPED THROUGH SQLAlchemy
from contacts c
inner join
(select _c.last_name, count(_c.last_name) as dups from contacts _c group by _c.last_name) cd on c.last_name = cd.last_name
group by c.id, c.first_name, c.last_name, cd.dups
EDIT-1:
Forgot to mention that I am using the ORM where my Contact object is mapped to contacts table. I'll be more specific about what I am trying to achieve. When selecting the contacts based on a specific criteria I have to return an 'extra column' which says how many times the last_name is found in contacts table.

Had hard time with how a labeled column should be used.
subq = self.db_context.query(Contact._last_name, label('dups', func.count(Contact._last_name))) \
.group_by(Contact._last_name) \
.subquery('dup_contacts')
dup_contacts = aliased(Contact, subq)
contacts = self.db_context.query(Contact, 'dups').filter(Contact._last_name.ilike(_contact_last_name)) \
.join(dup_contacts, and_(Contact._last_name == dup_contacts._last_name)) \
.all()

Related

Connecting multiple tables with different foreign keys SQL

I am struggling in finding the solution on how to connect 5 different tables, but with different foreign keys. The table looks like that:
I need to write a query that would return all customers visit costs and payment differences (debt or overpay) and the last payment date on selected dates:
SELECT Cusomer ID, Name, Surname, SUM(Visit fee + materials price sum + service sum) - SUM(Payment amount) AS pay_diff, MAX(payment_date) WHEN DATE IS BETWEEN (LAST MONTH) AND (TODAY)
Expected Output choosing between 01-07-2021 and today:
Update: my SQL tables and db response:
customers
customer_visit
visit_services
visit_materials
customer_payments:
Query calculations:
select c.ID, c.Name, c.Surname
sum(cv.visit_fee) + sum(vm.Price_sum) + sum(vs.Service_sum) - sum(cp.Payment_amount) as pay_diff, max(payment_date)
from customer c
left join customer_visit cv
on c.ID = cv.customer_id
left join Visit_materials vm
on cv.ID = vm.Visit_ID
left join Visit_services vs
on cv.ID = vs.Visit_ID
left join Customer_payment cp
as c.ID = cp.Customer_id
where Payment_date >= '01-07-2021'
group by c.ID, c.Name, c.Surname
I noticed that the column names are inconsistent (diagram vs. table samples), you may need to adjust according to actual DB. If you got future date data, you can use between '01-07-2021' and 'xx-xx-2021' inside where clause. I hope it helps. If you get errors, can you post a screenshot of the error message?

NOT LIKE on mysql query

I have a big problem understanding why a query works when using LIKE in query and not working when using NOT LIKE.
I will post query below:
select DISTINCT (mails), name
from disposable
JOIN (
SELECT DISTINCT (mail) as mails,
CONCAT(toys.firstname, ' ' , toys.lastname) as name
FROM toys2
join toys ON toys.userid = toys2.id
where ( (toyid = '27' or toyid = '29')
and status != 'Sold'
and toys.regdate >= '2017-01-01'
)
) as tab
WHERE tab.mails LIKE CONCAT('%#', disposable.email)
I think what you want is something more like the following. Note that I simplified the schema a bit so as to do a bit less work for the SQL Fiddle.
SELECT c.email, c.name
FROM customer c LEFT JOIN disposable d
ON SUBSTR(c.email, INSTR(c.email, '#')+1, LENGTH(c.email)-INSTR(c.email, '#')) = d.email
WHERE d.email IS NULL;
Basically, here you're getting the domain of the customer and matching it to the entry in the disposable table. The final WHERE clause uses IS NULL to determine the customer email addresses that are not disposable - use IS NOT NULL to find the ones that are.
Hope this helps.

Nesting a max(date) statement in a mysql INNER JOIN

I'm having difficult with the logic/syntax surrounding a nested 'select max(date)' style statement. Let me try to explain. I have three tables that my statement is pulling data from:
Table #1 (table1_companies)
[id, companyname, industry]
Table #2: (table2_companydata)
[id, companyname, data, date_added]
Table #3: (table3_watchlist)
[id, companyname, usernane]
The statement I'm attempting to execute takes a company name from the Table 3, INNER JOINS the 'industry' from Table 1 and then INNER JOINS the latest company info (based on the last date) from Table 2. It is Table 2 that can have many rows per company, I just need the last one based on the latest date that was added. My current (simplified) statement without the attempt to grab the last date is:
SELECT
table1_companies.industry,
table2_companydata.data,
table3_watchlist.*
FROM
table3_watchlist
INNER JOIN table1_companies ON table1_companies.companyname = table3_watchlist.companyname INNER JOIN table2_companydata ON table2_companydata.companyname = table3_watchlist.companyname WHERE username='username'");
I think I need to insert a "SELECT max(date_added) FROM table2_companydata" into the 2nd INNER JOIN. But I've had no success with either logic or syntax. Can any enlighten me?
Do the joins and then select the last record. Here is one method using a where clause for the logic:
SELECT c.industry, cd.data, w.*
FROM table3_watchlist w INNER JOIN
table1_companies c
ON c.companyname = w.companyname INNER JOIN
table2_companydata cd
ON cd.companyname = w.companyname
WHERE username = 'username' AND
cd.date_added = (select max(cd2.date_added)
from table2_companydata cd2
where cd2.companyname = cd.companyname
);

Why calling JOIN after we already found data from inner SELECT?

in the SQL statement below, why do we have to use this last JOIN on total_sellers_month?
SELECT
best.*
FROM
(SELECT
rm.rc_year,
rm.rc_month,
(SELECT vm.vd_id
FROM total_sellers_month vm
WHERE vm.rc_year = rm.rc_year AND vm.rc_month = rm.rc_month
ORDER BY rc_total DESC LIMIT 1
) AS vd_id
FROM total_months rm
) AS best
JOIN sellers v ON (v.vd_id = best.vd_id)
JOIN total_sellers_month rm
ON (rm.vd_id = best.vd_id AND rm.rc_year = best.rc_year AND rm.rc_month = best.rc_month )
ORDER BY rc_year, rc_month;
We have the second SELECT that already gives us the year, month, and id depending on the best months/years :
(SELECT
rm.rc_year,
rm.rc_month,
(SELECT vm.vd_id
FROM total_sellers_month vm
WHERE vm.rc_year = rm.rc_year AND vm.rc_month = rm.rc_month
ORDER BY rc_total DESC LIMIT 1
) AS vd_id
FROM total_months rm
) AS best
Then we add the sellers to have some more informations (the name of each seller, etc.), and the we repeat the call to total_sellers_month with a Join :
JOIN total_sellers_month rm
ON (rm.vd_id = best.vd_id AND rm.rc_year = best.rc_year AND
Why don't we just use a JOIN on "sellers"? The data we retrieved from the inner SELECT is not enough to be recognized as a table for the join?
As far as I can see you would only join from best onto total_sellers_month to get columns you did not gather from the derived table. This can be a valid technique where best is simply the way to locate the rows that you need, but then must join back to the source table for access to those complete source rows.
However as you are displaying only "select best.*" in the question there isn't a purpose to any of the joins. Perhaps this may be due to simplification for the question.

Grouping method

I am working on a query with the following format:
I require all the columns from the Database 'A', while I only require the summed amount (sum(amount)) from the Database 'B'.
SELECT A.*, sum(B.CURTRXAM) as 'Current Transaction Amt'
FROM A
LEFT JOIN C
ON A.Schedule_Number = C.Schedule_Number
LEFT JOIN B
ON A.DOCNUMBR = B.DOCNUMBR
ON A.CUSTNMBR = B.CUSTNMBR
GROUP BY A
ORDER BY A.CUSTNMBR
My question is regarding the grouping statement, database A has about 12 columns and to group by each individually is tedious, is there a cleaner way to do this such as:
GROUP BY A
I am not sure if a simpler way exists as I am new to SQL, I have previously investigated GROUPING_ID statements but thats about it.
Any help on lumped methods of grouping would be helpful
Since the docnumber is the primary key - just use the following SQL:
SELECT A.*, sum(B.CURTRXAM) as 'Current Transaction Amt'
FROM A
LEFT JOIN C
ON A.Schedule_Number = C.Schedule_Number
LEFT JOIN B
ON A.DOCNUMBR = B.DOCNUMBR
ORDER BY RM20401.CUSTNMBR
GROUP BY A.DOCNUMBR